Threads not waking up when notify_all() is called - c++

I am trying to write a simple, thread-safe blocking queue for my application. For whatever reason in my demo app, not all threads are waking up when the call to close() is made. My consumer thread closes just fine but the other 2 producer threads never receive the signal. Perhaps a race condition?
This is my demo application:
#include <iostream>
#include <string>
#include <sstream>
#include <mutex>
#include "blocking_queue.h"
rl::blocking_queue<std::string> queue(3);
std::string random_string(size_t);
int main()
{
std::thread consumer([]() {
std::string message;
while (queue.pop(message)) {
std::cout << "--> async_write(...) called with:" << message << std::endl;
std::thread popper([]() {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "--> async_write(...) completed, queue size is now " << queue.size() << std::endl;
queue.unblock();
});
popper.detach();
if (!queue.block()) {
break;
}
}
std::cout << "consumer thread closed" << std::endl;
});
std::thread producer([]() {
while (!queue.closed()) {
std::string id = random_string(6);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << id << ": Pushing JSON" << std::endl;
queue.push("a message");
std::cout << id << ": Pushed JSON" << std::endl;
}
std::cout << "producer closed" << std::endl;
});
std::thread producer2([]() {
while (!queue.closed()) {
std::string id = random_string(6);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::cout << id << ": Pushing heartbeat" << std::endl;
queue.push("a heartbeat");
std::cout << id << ": Pushed heartbeat" << std::endl;
}
std::cout << "producer2 closed" << std::endl;
});
std::thread cancel([]() {
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
std::cout << "%%%% CLOSING QUEUE %%%%" << std::endl;
queue.close();
std::cout << "%%%% QUEUE CLOSED %%%%" << std::endl;
});
cancel.join();
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
std::cout << "Hello World!\n";
return EXIT_SUCCESS;
}
std::string random_string(size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
This is my blocking queue:
#include <queue>
#include <mutex>
#include <condition_variable>
#include <assert.h>
// Based on https://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
namespace rl {
template<typename T>
class blocking_queue {
private:
std::queue<T> queue;
const size_t queue_limit;
bool is_closed = false;
mutable std::mutex queue_mutex;
std::condition_variable new_item_or_closed_event;
std::condition_variable item_removed_event;
std::condition_variable queue_blocked_event;
#ifndef NDEBUG
size_t pushes_in_progress = 0;
#endif
public:
blocking_queue(size_t size_limit = 0) : queue_limit(size_limit) {}
void push(const T& data) {
std::unique_lock<std::mutex> lock(queue_mutex);
#ifndef NDEBUG
++pushes_in_progress;
#endif
if (queue_limit > 0) {
while (queue.size() >= queue_limit) {
item_removed_event.wait(lock);
}
}
assert(!is_closed);
queue.push(data);
#ifndef NDEBUG
--pushes_in_progress;
#endif
lock.unlock();
new_item_or_closed_event.notify_one();
}
bool try_push(const T& data) {
std::unique_lock<std::mutex> lock(queue_mutex);
if (queue_limit > 0) {
if (queue.size() >= queue_limit) {
return false;
}
}
assert(!is_closed);
queue.push(data);
lock.unlock();
new_item_or_closed_event.notify_one();
return true;
}
void close() {
std::unique_lock<std::mutex> lock(queue_mutex);
assert(!is_closed);
#ifndef NDEBUG
assert(pushes_in_progress == 0);
#endif
is_closed = true;
lock.unlock();
//item_removed_event.notify_all();
//queue_blocked_event.notify_all();
new_item_or_closed_event.notify_all();
}
void open() {
is_closed = false;
}
bool block() {
std::unique_lock<std::mutex> lock(queue_mutex);
queue_blocked_event.wait(lock);
return !is_closed;
}
void unblock() {
queue_blocked_event.notify_one();
}
bool pop(T & popped_value) {
std::unique_lock<std::mutex> lock(queue_mutex);
while (queue.empty()) {
if (is_closed) {
return false;
}
new_item_or_closed_event.wait(lock);
}
popped_value = queue.front();
queue.pop();
item_removed_event.notify_one();
return true;
}
bool try_pop(T & popped_value) {
std::unique_lock<std::mutex> lock(queue_mutex);
if (queue.empty()) {
return false;
}
popped_value = queue.front();
queue.pop();
item_removed_event.notify_one();
return true;
}
bool empty() const {
std::unique_lock<std::mutex> lock(queue_mutex);
return queue.empty();
}
bool closed() const {
std::unique_lock<std::mutex> lock(queue_mutex);
return is_closed;
}
size_t limit() const {
return queue_limit;
}
size_t size() const {
std::unique_lock<std::mutex> lock(queue_mutex);
return queue.size();
}
};
}

Related

Single producer / multiple consumer deadlock

The following code reasults in a deadlock. The problem is that I cannot figure out how unlock the consumers waiting on the condition variable. The consumer should loop and consume from the stack when a certain condition is met. I've tried exiting when the stack is empty but of course it doesn't work.
Stack.h
class Stack {
private:
std::stack<int> stack;
std::mutex mutex;
std::condition_variable is_empty;
bool done;
public:
Stack();
void push(int);
void pop();
void print();
bool isDone() const;
~Stack();
};
Stack.cpp
#include <iostream>
#include <sstream>
#include <thread>
#include "Stack.h"
void Stack::push(int x) {
std::lock_guard lock(mutex);
std::stringstream msg1;
msg1 << "producer " << std::this_thread::get_id() << " pushing " << x << std::endl;
std::cout << msg1.str();
stack.push(x);
std::stringstream msg;
msg << "producer " << std::this_thread::get_id() << ": " << x << " pushed" << std::endl;
std::cout << msg.str();
is_empty.notify_all();
}
void Stack::pop() {
std::unique_lock lock(mutex);
std::stringstream msg;
msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
std::cout << msg.str();
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
is_empty.notify_all();
}
}
void Stack::print() {
std::lock_guard lock(mutex);
for (int i = 0; i < stack.size(); i++) {
std::cout << "\t" << stack.top() << std::endl;
}
}
Stack::~Stack() {
}
bool Stack::isDone() const {
return done;
}
Stack::Stack() : done(false) {}
main.cpp
#include <thread>
#include <vector>
#include <iostream>
#include "Stack.h"
int main() {
Stack stack;
std::vector<std::thread> producer;
std::vector<std::thread> consumer;
for (int i = 0; i < 10; i++) {
consumer.emplace_back([&stack]{
while (!stack.isDone()) {
stack.pop();
}
});
}
for (int i = 0; i < 1; i++) {
producer.emplace_back([&stack]{
for (int j = 0; j < 5; ++j) {
stack.push(random());
}
});
}
for (int k = 0; k < producer.size(); k++) {
producer[k].join();
std::cout << producer[k].get_id() << " joined" << std::endl;
stack.print();
}
for (int j = 0; j < consumer.size(); j++) {
consumer[j].join();
std::cout << consumer[j].get_id() << " joined" << std::endl;
stack.print();
}
return 0;
}
Your code is not deadlocked but your threads are waiting for more input because you haven't configure the value of done properly.
There is no way that the else condition is invoked here
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
is_empty.notify_all();
}
Looking from the code it seems like what you want is that after the producer stops producing the consumer should wake up and empty. But this is not the way to implement it. After the producer has pushed 5 elements you should set done =true from there.
Also as answered by madducci you need to change the location of notify_all();
This is something which worked for me
is_empty.wait(lock, [&] { return stack.size()>0 || done; });
if (!stack.empty()) {
int val=stack.top();
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped " <<val<<std::endl;
std::cout << msg1.str();
}
Looks like you have a logic error in your pop function: you never call notify_all() in case you pop an element from the stack.
The correct way should be this one:
void Stack::pop() {
std::unique_lock lock(mutex);
std::stringstream msg;
msg << "consumer " << std::this_thread::get_id() << " waiting to consume" << std::endl;
std::cout << msg.str();
is_empty.wait(lock, [this] { return !stack.empty(); });
if (!stack.empty()) {
stack.pop();
std::stringstream msg1;
msg1 << "consumer " << std::this_thread::get_id() << " popped" << std::endl;
std::cout << msg1.str();
} else {
done = true;
}
is_empty.notify_all();
}
You also invoke pop() before push() in your main

wait_until timeout causing only one thread to terminate, unable to catch all thread timeouts

I've made a simple thread-safe Buffer implementation, creating 10 threads to work on the buffer queue to push and pop randomly some numbers. My implementation should let threads that are waiting to pop to wait only for 3 seconds and then terminate. When that occurs I print a timeout message.
The problem is that only one timeout message is printed, the main will then join all threads and return. Why?
Here is the code, main.cpp
#include <thread>
#include <vector>
#include <iostream>
#include <sstream>
#include "Buffer.h"
int main() {
std::vector<std::thread> workers;
Buffer<std::string> buffer(3);
srandom(time(NULL));
for (int i = 0; i < 10; i++) {
workers.emplace_back([&buffer]{
long num = random();
if(num%2==0) {
std::stringstream msg;
msg << std::this_thread::get_id() << " pushing " << num << std::endl;
std::cout << msg.str();
buffer.push(std::to_string(num));
} else {
std::stringstream msg1;
msg1 << std::this_thread::get_id() << " waiting to pop" << std::endl;
std::cout << msg1.str();
std::string popped_string = buffer.pop();
std::stringstream msg2;
msg2 << std::this_thread::get_id() << " popped " << popped_string << std::endl;
std::cout << msg2.str();
}
});
}
for (auto &w: workers) {
if (w.joinable()) w.join();
}
return 0;
}
Buffer.h
#ifndef PDS_CPP_BUFFER_H
#define PDS_CPP_BUFFER_H
#include <queue>
#include <mutex>
#include <condition_variable>
template <class T>
class Buffer {
private:
std::queue<T> queue;
std::mutex mutex;
std::condition_variable cv;
std::chrono::seconds sec;
public:
Buffer(int time) : sec(time), queue() {};
void push(T object) {
std::lock_guard lockGuard(mutex);
this->queue.push(object);
this->cv.notify_one();
}
T pop() {
std::unique_lock uniqueLock(mutex);
// this->cv.wait(uniqueLock, [this]{ return !this->queue.empty(); });
if(this->cv.wait_for(uniqueLock, this->sec, [this]{ return !this->queue.empty(); })) {
} else {
std::stringstream msg;
msg << std::this_thread::get_id() << " timeout" << std::endl;
std::cout << msg.str();
}
T object = this->queue.front();
this->queue.pop();
uniqueLock.unlock();
return object;
}
};
#endif //PDS_CPP_BUFFER_H

condition_variable event notifyAndWait()

I have a loop that waits for the event.
I want to be able to add a notifyAndWait() function
Im not to sure how i can add that to my current class
class Event
{
public:
Event() : _signalled(false) {}
void notify()
{
std::unique_lock<std::mutex> lock(_mutex);
_signalled = true;
_condvar.notify_one();
}
void wait()
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _signalled; }); // also takes care about spurious wakeup
_signalled = false; // auto-reset semantics
}
private:
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled;
};
You could use the same condition variable to pass a signal back to the calling thread, using a different flag. Something like this:
class Event
{
public:
Event() : _signalled(false) {}
void notify()
{
std::cout << "notifying" << '\n' << std::flush;
{
std::unique_lock<std::mutex> lock(_mutex);
_completed = false;
_signalled = true;
}
_condvar.notify_one();
{
// now wait for completion
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _completed; });
}
std::cout << "completed" << '\n' << std::flush;
}
void wait()
{
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _signalled; });
_signalled = false;
}
// do stuff
auto n = hol::random_number(10);
std::cout << "doing " << n << " different things" << std::flush;
for(int i = 0; i < n; ++i)
{
std::cout << '.' << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(hol::random_number(3000)));
}
std::cout << " done stuff" << '\n' << std::flush;
{
std::unique_lock<std::mutex> lock(_mutex);
_completed = true;
}
_condvar.notify_one();
}
private:
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled;
bool _completed;
};
int main()
{
Event e;
std::thread wait([&]{ e.wait(); });
e.notify();
wait.join();
}

pausing a thread that is waiting for input?

I'm writing a chess engine , and this is an example of how I want to implement the UCI protocol:
//search.h
#pragma once
#include<atomic>
static std::atomic_bool stop=false;
namespace Search
{
int Alphabeta()
{
int r = 10;
int Rounds = 0;
while ((++Rounds<20)&&!stop)
{
int sum = 0;
for (size_t i = 0; i < 100000000; i++)
{
sum += i;
}
sync_cout << sum<< sync_endl;
}
sync_cout << "Stopping" << sync_endl;
return r;
}
}
//UCI.h
#pragma once
#include<iostream>
#include<string>
#include <sstream>
#include<thread>
#include<mutex>
#include<condition_variable>
enum SyncCout { IO_LOCK, IO_UNLOCK };
//taken from StockFish
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
static std::mutex m;
if (sc == IO_LOCK) m.lock();
if (sc == IO_UNLOCK) m.unlock();
return os;
}
#define sync_cout std::cout << IO_LOCK
#define sync_endl std::endl << IO_UNLOCK
#include"search.h"
class Thread
{
public:
Thread()
{
nativeThread = std::thread(&Thread::MainLoop, this);
sync_cout << "#Constructor" << sync_endl;
}
void MainLoop()
{
while (!exit)
{
while (pause)
{
sync_cout << "#Waiting" << sync_endl;
std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk);
lk.unlock();
}
sync_cout << "#UCILoop" << sync_endl;
std::string token, cmd;
while (!pause && !exit && std::getline(std::cin, cmd))
{
sync_cout << "#Processing" << sync_endl;
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "stop")
{
stop = true;
PauseThread();
}
else if (token == "isready") std::cout << "readyok" << std::endl;
else if (token == "pause") PauseThread();
}
}
}
void PauseThread()
{
//pause
std::lock_guard<std::mutex> lk(mutex);
pause = true;
}
void ResumeThread()
{
std::lock_guard<std::mutex> lk(mutex);
pause = false;
cv.notify_one();
}
~Thread()
{
sync_cout << "#Destructor" << sync_endl;
mutex.lock();
pause = false;
exit = true;
cv.notify_one();
mutex.unlock();
nativeThread.join();
}
private:
std::thread nativeThread;
std::mutex mutex;
std::condition_variable cv;
bool pause = true, exit = false;
};
namespace UCI
{
void Loop()
{
Thread th;
std::cout << "#PrimaryLoop : "<<std::endl;
std::string token, cmd;
while (std::getline(std::cin, cmd))
{
std::cout << "Processing : ";
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
std::cout << "go ok" << std::endl;
stop = false;
th.ResumeThread();
Search::Alphabeta();
th.PauseThread();
}
else if (token == "isready") std::cout << "readyok" << std::endl;
else if (token == "quiet")
{
std::cout << "quieting" << std::endl;
break;
}
}
}
}
and main :
#include"UCI.h"
int main()
{
UCI::Loop();
}
Everything works ok with the only exception being the case when the search finishes normally without receiving the UCI command "stop" , so the search will return while the secondary UCI thread is waiting for input #"std::getline" , I intended to write to the stdin stream "pause" as can be seen from the code before knowing that this is at the very best non portable & wrong , what are my options or is there another way to pause a thread regardless of what it's currently executing ?

Is it possible to build a concurrent interprocess message queue using boost?

I am trying to build an application which have multiple processes. These processes need to write concurrently through the same message queue. At the other side, there will be just one process reading that queue.
Is that possible using boost? Or do I have to implement that mutual exclusion?
I took a look at the example source code but it is not working properly for my needs. I don't know if I'm missing something.
This is the code on the client:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
#include <unistd.h>
using namespace boost::interprocess;
int main ()
{
try{
//Erase previous message queue
//message_queue::remove("message_queue");
//Create a message_queue.
message_queue mq
(open_or_create //only create
,"message_queue" //name
,100 //max message number
,sizeof(int) //max message size
);
//Send 100 numbers
for(int i = 0; i < 100; ++i){
printf("Sending: %d\n", i);
usleep(1000000);
mq.send(&i, sizeof(i), 0);
}
}
catch(interprocess_exception &ex){
std::cout << ex.what() << std::endl;
return 1;
}
return 0;
}
And server code:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::interprocess;
int main ()
{
try{
//message_queue::remove("message_queue");
//Open a message queue.
message_queue mq
(open_only //only create
,"message_queue" //name
);
unsigned int priority;
message_queue::size_type recvd_size;
//Receive 100 numbers
for(int i = 0; i < 100; ++i){
int number;
mq.receive(&number, sizeof(number), recvd_size, priority);
if(number != i || recvd_size != sizeof(number))
return 1;
cout << number << endl;
}
}
catch(interprocess_exception &ex){
message_queue::remove("message_queue");
std::cout << ex.what() << std::endl;
return 1;
}
//message_queue::remove("message_queue");
return 0;
}
Thanks in advance.
The given examples for boost::interprocess::message_queue work for me. These classes are already thread-safe, so intra-process threads are not a problem.
Here's a full example of a shared message queue. Let me know if you have trouble using it.
shared_mq.hpp:
#include <boost/interprocess/ipc/message_queue.hpp>
// could easily be made a template; make sure T is a POD!
class shared_mq {
public:
shared_mq(const char* const name,
const unsigned max_queue_size) :
shared_mq{ name, max_queue_size, delete_queue(name) }
{}
shared_mq(const char* const name) :
mq_{ boost::interprocess::open_only, name }
{}
void send(int i) {
mq_.send(&i, sizeof(i), 0 /* priority */);
}
int receive() {
int result;
boost::interprocess::message_queue::size_type recvsize;
unsigned recvpriority;
mq_.receive(&result, sizeof(result), recvsize, recvpriority);
return result;
}
private:
struct did_delete_t {};
did_delete_t delete_queue(const char* const name) {
boost::interprocess::message_queue::remove(name);
return did_delete_t{};
}
shared_mq(const char* const name,
const unsigned max_queue_size,
did_delete_t) :
mq_ { boost::interprocess::create_only, name, max_queue_size, sizeof(int) }
{}
boost::interprocess::message_queue mq_;
};
client.cpp:
#include <iostream>
#include <random>
#include <thread>
#include "shared_mq.hpp"
void send_ints(shared_mq& mq, const unsigned count) {
std::random_device rd;
std::mt19937 mt{ rd() };
std::uniform_int_distribution<int> dist{0, 10000};
for (unsigned i = 0; i != count; ++i) {
mq.send(dist(mt));
}
}
int main ()
{
std::cout << "Starting client." << std::endl;
try {
std::cout << "Creating queue..." << std::endl;
constexpr unsigned kQueueSize = 100;
shared_mq mq{ "my_queue", kQueueSize };
std::cout << "Sending ints..." << std::endl;
std::thread t1{ send_ints, std::ref(mq), 25};
std::thread t2{ send_ints, std::ref(mq), 25};
t1.join();
t2.join();
mq.send(-1); // magic sentinel value
}
catch (boost::interprocess::interprocess_exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "Finished client." << std::endl;
return 0;
}
server.cpp:
#include <iostream>
#include "shared_mq.hpp"
int main ()
{
std::cout << "Starting server." << std::endl;
try {
std::cout << "Opening queue..." << std::endl;
shared_mq mq{ "my_queue" };
std::cout << "Receiving ints..." << std::endl;
for (;;) {
const int x = mq.receive();
if (x == -1) {
// magic sentinel value
break;
}
std::cout << "Received: " << x << std::endl;
}
}
catch (boost::interprocess::interprocess_exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "Finished server." << std::endl;
return 0;
}