首页 > 解决方案 > 对象地址突然变了

问题描述

class test
{
    void thread1()
    {
        int i = 0;
        while(true){
            for(unsigned int k = 0;k < mLD.size(); k++ )
            {
                mLD[k] = i++;
            }
        }
    }
    void thread2()
    {
        std::cout << "thread2 address  : " << &mLD << "\n";
        C();
    }
    void B()
    {
        std::cout << "B address  : " << &mLD << "\n";
        for(unsigned int k = 0;k < mLD.size(); k++ )
        {
            if(mLD[k]<=25)
            {
            }
        }
    }
    void C()
    {
        B();
        std::cout << "C address  : " << &mLD << "\n";
        double distance = mLD[0];  //  <---- segmetation fault
    }
    std::array<double, 360> mLD;
};

cout 结果--->

线程2地址:0x7e807660

B地址:0x7e807660

C地址:0x1010160(有时是0x7e807660)

为什么mLD的地址变了……?

即使我将 std::array 更改为std::array<std::atomic<double>360>,结果也是一样的。

标签: multithreadingc++11segmentation-fault

解决方案


最有可能的是,您引用的对象在调用 C 时被销毁,这表明存在同步问题。您需要延长线程引用的对象的生命周期,直到线程完成执行其例程。要做到这一点,你可以有这样的东西;

#include <thread>
#include <array>
#include <iostream>

struct foo{
  void callback1(){
    for(auto & elem: storage){
      elem += 5;
    }
  }

  void callback2(){
    for(const auto & elem: storage){
      std::cout << elem << std::endl;
    }
  }

  std::array<double, 300> storage;
};

int main(void){
   foo f;
   std::thread t1 {[&f](){f.callback1();}};
   std::thread t2 {[&f](){f.callback2();}};

   // wait until both threads are done executing their routines

   t1.join();
   t2.join();
   return 0;
}

foo, f 的实例存在于 main() 函数的范围内,因此它的生命周期由它定义的行定义到 main 范围的末尾。通过加入两个线程,我们阻止 main 继续进行,直到两个线程都执行完它们的回调函数,因此 f 的生命周期延长,直到回调完成。

第二个问题是,代码需要同步原语,因为存储变量在两个独立的执行路径之间共享。正确同步的最终代码如下所示;

#include <thread>
#include <array>
#include <iostream>
#include <mutex>

struct foo{
  void callback1(){
    // RAII style lock, which invokes .lock() upon construction, and .unlock() upon destruction 
    // automatically.
    std::unique_lock<std::mutex> lock(mtx);
    for(auto & elem: storage){
      elem += 5;
    }
  }

  void callback2(){
    std::unique_lock<std::mutex> lock(mtx);
    for(const auto & elem: storage){
      std::cout << elem << std::endl;
    }
  }

  std::array<double, 300> storage;
  // non-reentrant mutex
  mutable std::mutex mtx;
};

int main(void){
   foo f;
   std::thread t1 {[&f](){f.callback1();}};
   std::thread t2 {[&f](){f.callback2();}};

   // wait until both threads are done executing their routines

   t1.join();
   t2.join();
   return 0;
}

推荐阅读