Reputation: 3350
It seems like condition_variable
notify_one
doesn't always work the way it should.
struct Task {
std::mutex mutex;
std::condition_variable cv;
std::atomic_bool launch{false};
};
void job(Task& task) {
std::unique_lock<std::mutex> lock{task.mutex};
task.cv.wait(lock, [&]{ return task.launch == true; });
}
int main() {
for (auto i=0 ; i<1000*1000 ; i++) {
Task task;
std::thread thread{job, std::ref(task)};
task.launch = true;
task.cv.notify_one();
thread.join();
}
}
This program will almost never reach the end, it stops forever in the loop a vast majority of the time. Why does that happen?
Upvotes: 1
Views: 670
Reputation: 17415
Two mistakes here:
atomic_bool
just causes overhead.launch
flag, you need to lock its mutex before writing to it. You don't do that in main()
.Explanation:
main()
creates task
main()
creates thread
job()
locks the mutexjob()
checks launch
, which is falsemain()
sets launch
main()
signals the CV, which nobody receivesjob()
waits for the CV due to the value of launch
in step 4Normally, steps 3 and 6 would be atomic because any other thread should not have touched launch
without locking the mutex. Since that didn't happen, the interleaving of dependent operations was allowed to take place, which finally caused the unexpected behaviour.
Upvotes: 4
Reputation: 36401
Not clear what you want, but your problem is that is may happen that the main realizes launch=true
and notify_one()
before the thread had time to call wait
. In this case, you should know that notify
is not delayed, thus your main will be blocked on join
while the thread is blocked on wait
.
Upvotes: 1