Адрес объекта неожиданно изменился - PullRequest
0 голосов
/ 31 октября 2019
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 --->

адрес thread2: 0x7e807660

Адрес B: 0x7e807660

C адрес: 0x1010160 (иногда0x7e807660)

Почему адрес mLD изменился ....?

даже если я изменил std :: array на std::array<std::atomic<double>360>, результат такой же.

1 Ответ

1 голос
/ 31 октября 2019

Скорее всего, указанный вами объект уничтожен в точке вызова 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 до тех пор, пока оба потока не завершат выполнение своих функций обратного вызова, поэтому время жизни 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;
}
...