boost :: thread и деструктор содержащихся классов - PullRequest
0 голосов
/ 29 августа 2011

Я хотел бы понять поведение этого кода.

class Foo
{
      public:
            Foo();
            ~Foo();
            void run();
            int* get();
    private:
            int *a;
};

Foo::Foo()
{
     a=NULL;       
}
void Foo::run()
{
       if ( a==NULL)
            a = new int[30000];
}

int* Foo::get()
{
    return a;
}

Foo::~Foo()
{
    cout << "destructor called" << endl;
    if ( a!=NULL)
            delete a;
}

int main()
{
        Foo *a = new Foo();

        boost::thread Foothread( &Foo::run, a);
        // Some very long computation that sometimes access 

        int *b  = a->get();
        cout << *b << endl; 
        //Foothread.join();
        //delete a;
        //Foothread.join();

        return 0;
}

Этот код вызывает утечку памяти в 120000 байт, потому что переменная a не уничтожается, поэтому, когда я явно удаляю ее, утечка уничтожается, и все должно быть в порядке.

Теперь, если вместо динамического выделения я использую статическое распределение, деструктор вызывается много раз !!!

int main()
{
        Foo a;

        boost::thread Foothread( &Foo::run, a);
        // Some very long computation that sometimes access "a"
        Foothread.join();
        int *b  = a.get();
        cout << *b << endl; 

        return 0;
}

и выход Деструктор вызвал, было 0 Теперь 0 Деструктор вызвал, было 0 Теперь 0 Деструктор вызвал, было 0 Теперь 0 Деструктор вызвал, было 0 Теперь 0 Деструктор вызвал, было 0 Теперь 0 Деструктор вызвал, было 0 Теперь 0 вызвал деструктор, был 0x75e300 Теперь 0 Ошибка сегментации

Деструктор называется N раз !!

Теперь я хотел бы знать, как безопасно распределять и освобождать как переменную-член класса, так и объекты, используя boost :: thread, и почему деструктор потока не обрабатывает деструктор класса явно.

Может ли кто-нибудь дать мне подсказку? Должен ли boost :: smart_ptr помочь мне? Я должен выделить память с помощью malloc (потому что мне нужно использовать какой-то старый C API), как я могу сделать это потокобезопасным?

Ответы [ 2 ]

1 голос
/ 29 августа 2011

Обе версии создают объект класса Foo в потоке 1 и вызывают его метод run из фонового потока (поток 2). Этот фоновый поток завершается, когда возвращается run.

run фактически инициализирует объект класса Foo. Одна проблема в вашем коде состоит в том, что вы можете сделать очень длинные вычисления, которые иногда обращаются к "a" в потоке 1 до того, как поток 2 завершит инициализацию a. Это вызывает состояние гонки. Чтобы избежать этого, вы должны позвонить Foothread.join(), прежде чем получить доступ к Foo::a в a.

Некоторые другие пункты:

  • в Foo :: ~ Foo () вам не нужно проверять, отличается ли указатель для удаления от NULL
  • массив a, созданный с помощью new, должен быть удален с помощью delete[] a;
1 голос
/ 29 августа 2011

Должно ли это быть & a во втором случае?

boost::thread Foothread( &Foo::run, &a);
...