Reputation: 3
The below code doesn't block the thread and it gets into an infinite loop and keep printing
Waiting...
Waiting...
My idea is, the thread should block on the max() time and when it's set to now(), it should unblock the thread and do the business. Any ideas? I am using VS2013
#include "stdafx.h"
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <chrono>
std::condition_variable condVar;
std::mutex mut;
bool pred = false;
auto dueAt = std::chrono::steady_clock::time_point::max();
void threadFunc()
{
for (;;)
{
std::unique_lock<std::mutex> lock(mut);
dueAt = std::chrono::steady_clock::time_point::max();
if (condVar.wait_until(lock, dueAt, [](){ return pred; }))
{
std::cout << "Ready..." << std::endl;
pred = false;
dueAt = std::chrono::steady_clock::time_point::max();
}
else
{
std::cout << "Waiting..." << std::endl;
}
}
}
void notifierThread()
{
for (int i = 0; i < 5; i++)
{
std::this_thread::sleep_for(std::chrono::seconds(5));
{
std::lock_guard<std::mutex> lock(mut);
dueAt = std::chrono::steady_clock::now();
pred = true;
std::cout << " Signalling..." << std::endl;
}
condVar.notify_one();
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::thread t1(threadFunc);
std::thread t2(notifierThread);
t1.join();
t2.join();
return 0;
}
Upvotes: 0
Views: 91
Reputation: 275820
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_until
ing 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.
Upvotes: 0