-1
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 result --->

thread2 address : 0x7e807660

B address : 0x7e807660

C address : 0x1010160 (sometimes 0x7e807660 )

Why mLD's address changed ....?

even i change std::array to std::array<std::atomic<double>360>, the result is the same.

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
Samuel
  • 803
  • 8
  • 17

1 Answers1

1

Most probably, the object you referred is destroyed at the point of call to C, which points to a synchronization issue. You need to extend the lifetime of the object referred by thread(s), until the threads done executing their routine. To accomplish this, you can have something like this;

#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;
}

The instance of foo, f lives in scope of main() function, so its' lifetime is defined by from the line it defined to end of the main's scope. By joining both threads, we block main from proceeding further until both threads are done executing their callback functions, hence the lifetime of f extended until callbacks are done.

The second issue is, the code needs synchronization primitives, because storage variable is shared between two independent execution paths. The final code with proper synchronization can look like this;

#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;
}