In the following code I've a worker thread which is going to have one major state - Started. Started isn't the thread launch state but the state when a blocking call finally returns which I've replaced with a random delay and comment.
What I'm trying here is to first launch the worker thread asap, block on it's blocking call while keeping started = false
till it doesn't returns. As soon as it returns, I'll put started = true
and notify main
thread's infinite loop to launch another thread and wait again. The previous worker thread can resume doing its work now. And then repeat this process. The launch of new thread must wait for the START state of previous thread.
But in my previous question, someone mentioned this -
If cv.notify_one is called before cv.wait is running the notification will be missed. In the presented code it most probably will.
For now I tried to manually test it in various ways possible but couldn't get an error and everything is working as I thought. So I want to know in what situation will it actually miss it, anyway to make it reproducible, and how to actually solve it if it is a problem?
#include <iostream>
#include <string>
#include <mutex>
#include <condition_variable>
#include <future>
#include <atomic>
#include <chrono>
#include <thread>
#include <random>
std::mt19937_64 eng{std::random_device{}()};
std::uniform_int_distribution<> dist{100, 2000};
std::mutex m;
std::condition_variable cv;
bool started = false;
std::atomic<int> count(0);
void worker_thread()
{
std::unique_lock<std::mutex> lk(m);
int local_cnt = count++;
// some blocking call represented by random delay
std::this_thread::sleep_for(std::chrono::milliseconds{dist(eng)});
std::cerr << "Enter Accept: " << local_cnt << "\n";
started = true;
lk.unlock();
cv.notify_one(); // notify to launch other threads
// complete other work here
std::this_thread::sleep_for(std::chrono::milliseconds{dist(eng) + 2000});
std::cerr << "Exit Accept: " << local_cnt << "\n";
}
int main()
{
while(1){
std::thread(worker_thread).detach();
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return started;});
started = false;
}
}