【问题标题】:Object address suddenly changed对象地址突然变了
【发布时间】:2019-10-31 07:10:33
【问题描述】:
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;
};

计算结果--->

thread2地址:0x7e807660

B地址:0x7e807660

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

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

即使我将 std::array 更改为std::array&lt;std::atomic&lt;double&gt;360&gt;,结果也是一样的。

【问题讨论】:

标签: multithreading c++11 segmentation-fault


【解决方案1】:

很可能,您引用的对象在调用 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;
}

【讨论】:

  • @n.m.不用客气,我在移动,直到现在才意识到。
  • @n.m.亲爱的先生,这是一个答案吗?希望你现在开心:)
  • 这当然是一个答案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 2019-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多