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();
}
Related
I test the code below, producer thread can't run, but remove the line std::this_thread::sleep_for(std::chrono::seconds(1));,
it can work, why?
I know consumer thread existed an infinite loop
#include <algorithm>
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <queue>
#include <chrono>
using namespace std;
int main() {
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
std::thread producer([&]() {
pthread_setname_np("producer");
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(m);
std::cout << "producing " << i << '\n';
produced_nums.push(i);
notified = true;
cond_var.notify_one();
}
done = true;
cond_var.notify_one();
});
std::thread consumer([&]() {
pthread_setname_np("consumer");
std::unique_lock<std::mutex> lock(m);
while (!done) {
while (!notified) {
// cond_var.wait(lock);
}
while (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << endl;
produced_nums.pop();
}
notified = false;
}
});
producer.join();
consumer.join();
std::cout << "end" << endl;
}
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
I am trying to implement the analog of unique_lock (it's just studying task, I understand that standard library implementation works perfectly).
I've already written all the methods that I need and now I am trying to test my code on the example from https://en.cppreference.com/w/cpp/thread/unique_lock/unique_lock.
When it comes to std::lock(lk_b, lk_c); the infinite loop starts.
I did some cout's to understand where the program loses control and the result is the following: lock -> try -> unlock -> lock -> try -> unlock.
Here is partial unique_lock implementation (I included only those methods, which are used in the problem part of the example).
template<typename Mutex>
class my_unique_lock {
Mutex *lockable;
bool is_acquired;
public:
explicit my_unique_lock(Mutex& m): lockable{&m}, is_acquired{true}{
lockable->lock();
//std::cout << "constructor my_unique_lock(Mutex& m)" << std::endl;
}
my_unique_lock(Mutex& m, std::defer_lock_t t): lockable{&m}, is_acquired{false}{
std::cout << "constructor my_unique_lock(Mutex& m, std::defer_lock_t t)" << std::endl;
}
bool try_lock(){
std::cout << "try_lock" << std::endl;
if(lockable == nullptr)
throw std::system_error();
is_acquired = mutex()->try_lock();
return is_acquired;
}
void lock(){
std::cout << "lock" << std::endl;
if(lockable == nullptr || owns_lock())
throw std::system_error();
mutex()->lock();
is_acquired = true;
}
void unlock(){
//std::cout << "unlock" << std::endl;
if(lockable == nullptr || !owns_lock())
throw std::system_error();
mutex()->unlock();
is_acquired = false;
std::cout << "unlocked" << std::endl;
}
Mutex *mutex() const noexcept {
//std::cout << "*mutex()" << std::endl;
return lockable;
}
bool owns_lock() const noexcept {
//std::cout << "owns_lock()" << std::endl;
return lockable != nullptr && is_acquired;
}
~my_unique_lock(){
//std::cout << "destructor" << std::endl;
if(mutex() != nullptr && owns_lock()){
mutex()->unlock();
is_acquired = false;
}
}
};
And here is the example.
void update(std::mutex &m_a, std::mutex &m_b, std::mutex &m_c, int &a, int &b, int &c)
{
{
my_unique_lock<std::mutex> lk(m_a);
a++;
}
{
my_unique_lock<std::mutex> lk_b(m_b, std::defer_lock);
my_unique_lock<std::mutex> lk_c(m_c, std::defer_lock);
std::lock(lk_b, lk_c);
b = std::exchange(c, b + c);
}
}
int main()
{
std::mutex m_a, m_b, m_c;
int a, b, c = 1;
std::vector<std::thread> threads;
for (unsigned i = 0; i < 1; ++i)
threads.emplace_back(update, std::ref(m_a), std::ref(m_b), std::ref(m_b), std::ref(a), std::ref(b), std::ref(c));
for (auto& i: threads)
i.join();
std::cout << a << "'th and " << a+1 << "'th Fibonacci numbers: "
<< b << " and " << c << '\n';
}
So, as I said, I don't really understand why lock() causes the endless loop with such a chain of calls (lock -> try_lock -> unlocked).
Change std::ref(m_b), std::ref(m_b) to std::ref(m_b), std::ref(m_c). Copy/paste typo.
Your std::lock is trying to lock m_b twice.
Other issues: you violate rule of 0/3/5. You have multiple different near-identical lock fiddling for lock/unlock code (refactor).
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();
}
};
}
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 ?