2015-06-26 7 views
1

Мой объект создает поток, и этот поток изменяет объект-создателя в течение его жизненного цикла. Проблема в том, что этот поток не должен вызывать методы объектов при его уничтожении. Я нашел какое-то решение для этой проблемы, и я хотел бы знать, лучше ли это.Тестирование, если объект не удален

class A 
{ 
    shared_ptr<int> guard = make_shared<int>(0); 
public: 
    weak_ptr<int> getGuard() { return guard; } 
    void method() {} 
    A() 
    { 
     thread([this] 
     { 
      const auto &guard = getGuard(); 
      while(!guard.expired()) 
       method(); 
     }); 
    } 
}; 
+1

Вы намерены отсоединить поток, который создается, чтобы поток не блокировал конструктор 'A'? –

+0

Да, в реальном коде, конструкция нити не блокирует основной поток. Честно говоря, новый поток даже не создан в costructor. Я просто попытался немного упростить пример. –

ответ

1

Если вы хотите, чтобы убедиться, что объект не уничтожается, а вы звоните в method, но может быть уничтожен в другое время, вам необходимо держите weak_ptr на самом объекте и заблокируйте его, пока вы вызываете метод. Что-то вроде:

class A : std::enable_shared_from_this<A> 
{ 
public: 
    void method() {} 
    A() 
    { 
     std::weak_ptr<A> self(shared_from_this()); 
     thread([=self] 
     { 
      while (auto This = self.lock()) 
       This->method(); 
     }).detach(); 
    } 
}; 

Этот объект теперь может быть создан только с помощью make_shared - пытаться сделать это какие-либо другие результаты путь к неопределенному поведению и, вероятно, аварии.

3

Петля пока есть не поточно-безопасный способ обеспечения method только вызывается, а объект, на который указывает guard все еще существует. Причина этого в том, что другой поток может привести к уничтожению объекта между вызовом expired и вызовом method.

безопасный способ выполнить эту проверку, чтобы попытаться продвинуть слабый указатель на общий указатель:

while (true) 
{ 
    shared_ptr<int> sp = getGuard().lock(); 
    if (sp) 
    { 
     method(); 
    } 
    else 
    { 
     return; 
    } 
} 

Способствуя слабый указатель на общий указатель, то вызывающий код участвует в собственности на объект на время вызова method, гарантируя, что он не может быть уничтожен во время использования вызывающего кода.

Вы также не смогли подключить или отсоединить нить. Из вашего примера видно, что вы хотите отделить его так, чтобы конструктор A мог выйти, прежде чем поток завершит выполнение. В этом случае ваш код должен выглядеть следующим образом:

thread([this] 
{ 
    ... 
}).detach(); 
+0

Первая часть вашего ответа очень важна для меня. Я пропустил эту нить без внимания. Продвижение указателя не поможет (он указывает на члена класса, а не на объект), но обработка этих строк с помощью некоторых мьютексов будет выполнять эту работу. Это какой-то псевдокод, чтобы проиллюстрировать общую идею, в любом случае спасибо за предложение о detach(). Спасибо! –

+0

Это не очень помогает - блокировка предотвратит уничтожение общего 'int', а не объекта. Таким образом, вы все равно можете получить блокировку, затем другой поток уничтожает объект, затем вы вызываете метод на уничтоженном объекте. Вам нужно оставить 'weak_ptr' самому объекту и заблокировать его. –

+0

@ Chris Dodd Вы правы, я не продумал все детали, я больше интересовался проверкой цикла while. Не стесняйтесь редактировать это в этом ответе или оставить новый, иначе мне придется вернуться к этому позже, чтобы убедиться, что деталь добавлена. –

Смежные вопросы