Пытаясь расширить в двух моих предыдущих вопросов Move operations for a class with a thread as member variable и Call function inside a lambda passed to a threadC++ поток тупиковый на ожидание состояния
Я не понимая, почему нить делает wait_for является Somtimes не уведомила результаты Wich в тупике. Cppreference говорит о состоянии переменных http://en.cppreference.com/w/cpp/thread/condition_variable/notify_one
Уведомляющая нити не нужно удерживать блокировку на тот же мьютекс, как один, принадлежащей резьба (ами) ожидания; на самом деле это пессимизация, так как уведомляемый поток немедленно блокируется снова, ожидая, что уведомляющий поток освободит блокировку.
MCVE, комментируемая линия объясняет, что изменится, если я держу замок, но я не undrestand почему:
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
using namespace std;
class worker {
public:
template <class Fn, class... Args>
explicit worker(Fn func, Args... args) {
t = std::thread(
[&func, this](Args... cargs) -> void {
std::unique_lock<std::mutex> lock(mtx);
while (true) {
cond.wait(lock, [this]() -> bool { return ready; });
if (terminate) {
break;
}
func(cargs...);
ready = false;
}
},
std::move(args)...);
}
~worker() {
terminate = true;
if (t.joinable()) {
run_once();
t.join();
}
}
void run_once() {
// If i dont hold this mutex the thread is never notified of ready being
// true.
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cout << "ready run once " << ready << endl;
cond.notify_all();
}
bool done() { return (!ready.load()); }
private:
std::thread t;
std::atomic<bool> terminate{false};
std::atomic<bool> ready{false};
std::mutex mtx;
std::condition_variable cond;
};
// main.cpp
void foo() {
worker t([]() -> void { cout << "Bark" << endl; });
t.run_once();
while (!t.done()) {
}
}
int main() {
while (true) {
foo();
}
return 0;
}
Это «ready = true:», которое должно произойти под мьютексом. Не имеет значения, что это атомный. – Cubbi
@ user2079303 Исправлено! Тем не менее его трудно увидеть, если исполнение «истекает». – Aram
@ user2079303 Это не мгновенный тупик, по крайней мере, на моем компьютере. Вот почему я поставил цикл, чтобы я мог вызвать функцию несколько раз. – Aram