Your compiler is old and has bugs?
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <chrono>
std::condition_variable condVar;
std::mutex mut;
bool pred = false;
bool shutdown = false;
int result = 0;
void threadFunc()
{
for (;;)
{
std::unique_lock<std::mutex> lock(mut);
condVar.wait(lock, [](){ return pred || shutdown; });
if (shutdown) {
std::cout << "Shutdown!" << std::endl;
break;
}
std::cout << "Ready... #" << result << std::endl;
pred = false;
++result;
}
}
void notifierThread()
{
for (int i = 0; i < 5; i++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard<std::mutex> lock(mut);
pred = true;
std::cout << " Signalling... #" << i << std::endl;
}
condVar.notify_one();
}
}
int main()
{
std::thread t1(threadFunc);
std::thread t2(notifierThread);
t2.join();
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> l(mut);
if (result == 5)
{
std::cout << " Signalling Shutdown!" << std::endl;
shutdown = true;
break;
}
}
condVar.notify_one();
t1.join();
return 0;
}
here is a complete terminating version of your program that does not use dueAt.
Manipulating dueAt while you are .wait_untiling should do nothing (barring UB due to a race condition, which you avoided with a lock). It appears your C++ std implementation has a bug.
What, exactly, you where trying to do isn't clear, so I converted your code into something that (probably) halts.
In practice, you can't assume that sending 5 signals this way results in 5 receptions, as the sleep(100 ms) isn't guaranteed to give the reader thread to read. A more proper program would send a counter:
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <chrono>
std::condition_variable condVar;
std::mutex mut;
int counter = 0;
bool shutdown = false;
int consumed = 0;
void threadFunc()
{
for (;;)
{
std::unique_lock<std::mutex> lock(mut);
auto old_count = counter;
condVar.wait(lock, [old_count](){ return (counter != old_count) || shutdown; });
if (shutdown) {
std::cout << "Shutdown!" << std::endl;
break;
}
std::cout << "Ready... #" << old_count << ".." << counter << std::endl;
consumed = counter;
}
}
void notifierThread()
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
for (int i = 0; i < 5; i++)
{
if (i%2)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
{
std::lock_guard<std::mutex> lock(mut);
++counter;
std::cout << " Signalling... #" << i << " with count " << counter << std::endl;
}
condVar.notify_one();
}
}
int main()
{
std::thread t1(threadFunc);
std::thread t2(notifierThread);
t2.join();
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> l(mut);
if (consumed == 5)
{
std::cout << " Signalling Shutdown!" << std::endl;
shutdown = true;
break;
}
}
condVar.notify_one();
t1.join();
return 0;
}
here I make the producer be erratic, sometimes fast and sometimes slow. The consumer can handle more than 1 signal at a time however.
wait_untilcall can ever returnfalse(and print putWaiting...). When it is called,dueAtis set to max, so the timeout cannot be reached. And if the internal waiting in the loop is interrupted, the timeout is either still the same, or, if it has changed, thenpredhas changed totrueas well and the loop ends.wait_until()that blocks a thread permanently" — This does not make any sense.wait_untilbywait(plus get rid of that branching). ChangingdueAtinnotifierThreaddoesn't affect anything in this program.