Что происходит при вызове деструктора объекта потока, который ожидает переменную условия?

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

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

template <typename Type> class SynchronisedQueue {
public:
void Enqueue(Type const & data) {
std::unique_lock<std::mutex> lock(mutex_);
queue_.push(data);
condition_.notify_one();
}
Type Dequeue() {
std::unique_lock<std::mutex> lock(mutex_);
while (queue_.empty())
condition_.wait(lock);
Type result = queue_.front();
queue_.pop();
return result;
}
private:
std::queue<Type> queue_;
std::mutex mutex_;
std::condition_variable condition_;
};

class Worker {
public:
Worker(SynchronisedQueue<int> * queue) : queue_(queue) {}
void operator()() {
queue_->Dequeue();    // <-- The thread waits here.
}
private:
SynchronisedQueue<int> * queue_;
};

int main() {
auto queue = new SynchronisedQueue<int>();
Worker worker(queue);
std::thread worker_thread(worker);
worker_thread.~thread();  // <-- Crashes the program.
return 0;
}

7

Решение

Из спецификации C ++ 11:

30.3.1.3 деструктор потока [thread.thread.destr] ~ thread ();

Если joinable (), вызывает std :: terminate (). В противном случае не имеет никакого эффекта.

[Примечание: либо неявное отсоединение, либо присоединение к потоку joinable () в его деструкторе может привести к трудностям в отладке ошибок правильности (для отсоединения) или производительности (для объединения), возникающих только при возникновении исключения). Таким образом, программист должен гарантировать, что деструктор никогда не будет выполнен, пока поток все еще является присоединяемым. — конец примечания]

Так зовет thread destructor без первого звонка join (дождаться его окончания) или detach гарантированно немедленно позвонить std::terminate и закончить программу.

14

Другие решения

Деструктор для std::thread позвоню std::terminate если он запущен в потоке, если вы не вызвали join() (дождаться окончания потока) или detach() (чтобы отделить нить от объекта) на нем.

Ваш код вызывает деструктор для worker_thread без звонка join() или же detach() на нем и так std::terminate называется. Это не связано с наличием условных переменных.

2

Вы никогда не сможете уничтожить ресурс, пока что-то его использует или может использовать. Это действительно просто здравый смысл.

-1
По вопросам рекламы [email protected]