c++: condition variable ownership - c++

I am facing an issue while performing thread synchronisation.
I have a class very similar to the ThreadQueue implementation proposed in this answer, which I'll briefly report here for completeness:
#include <mutex>
#include <queue>
#include <condition_variable>
template <typename T>
class ThreadQueue {
std::queue<T> q_;
std::mutex mtx;
std::condition_variable cv;
public:
void enqueue (const T& t) {
{
std::lock_guard<std::mutex> lck(mtx);
q_.push(t);
}
cv.notify_one();
}
T dequeue () {
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [this] { return !q_.empty(); });
T t = q_.front();
q_.pop();
return t;
}
};
I have a consumer that continuously extracts the first available item of a shared instance of that class, say ThreadQueue<int> my_queue;, until it receives a signal to quit, for instance:
std::atomic_bool quit(false);
void worker(){
std::cout << "[worker] starting..." << std::endl;
while(!quit.load()) {
std::cout << "[worker] extract element from the queue" << std::endl;
auto el = my_queue.dequeue();
std::cout << "[worker] consume extracted element" << std::endl;
std::cout << el << std::endl;
}
std::cout << "[worker] exiting" << std::endl;
}
Suppose the program has to terminate (for any reason) before any producer can insert elements in the queue; in this case the worker would be stuck on the line auto el = my_queue.dequeue(); and cannot terminate.
An exemple of this case is the following:
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "[main] terminating..." << std::endl;
quit.store(true);
t.join();
std::cout << "[main] terminated!" << std::endl;
return 0;
}
Clearly, the worker can be "unlocked" by pushing a dummy element in the queue, but it does not seem an elegant solution.
I am thus wondering whether the thread syncronisation on the empty queue should be taken out of the ThreadQueue class and done inside the worker instead, i.e. moving the "ownership" of the condition variable outside the ThreadQueue container.
In general, is a class such as ThreadQueue always a bad design?
In case it's not, is there any solution that allows to keep the condition variable encapsulated in ThreadQueue, hence removing the responsibility of thread syncronisation from the users of that class (bearing in mind I am limited to usage of C++11)?
Full MWE here

The object that contains the mutex should also own the condition variable. So the ThreadQueue code looks good. But it is unclear what dequeue() should return when an asynchronous stop is requested.
A common way to solve this is to introduce either a quit flag or a sentinel value to the queue itself, a stop() method and a way for dequeue() to signal a closed queue, for example, using std::optional<T> as return value.
template <typename T>
class ThreadQueue {
std::queue<T> q_;
std::mutex mtx;
std::condition_variable cv;
bool quit = false;
public:
void enqueue (const T& t) {
{
std::lock_guard<std::mutex> lck(mtx);
q_.push(t);
}
cv.notify_one();
}
std::optional<T> dequeue () {
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [this] { return quit || !q_.empty(); });
if (quit) {
return {};
}
T t = q_.front();
q_.pop();
return t;
}
void stop() {
std::unique_lock<std::mutex> lck(mtx);
quit = true;
cv.notify_all();
}
};
Then when dequeue() returns an empty optional, the worker can exit gracefully.
void worker() {
std::cout << "[worker] starting..." << std::endl;
while (true) {
std::cout << "[worker] extract element from the queue" << std::endl;
auto el = my_queue.dequeue();
if (!el) {
std::cout << "[worker] exiting" << std::endl;
break;
}
std::cout << "[worker] consume extracted element" << std::endl;
std::cout << *el << std::endl;
}
std::cout << "[worker] exiting" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "[main] terminating..." << std::endl;
my_queue.stop();
t.join();
std::cout << "[main] terminated!" << std::endl;
return 0;
}

This is a quick hacky mod to your class to add stop function:
template <typename T>
class ThreadQueue {
std::queue<T> q_;
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> running = true;
public:
void enqueue (const T& t) {
{
std::lock_guard<std::mutex> lck(mtx);
q_.push(t);
}
cv.notify_one();
}
T dequeue () {
std::unique_lock<std::mutex> lck(mtx);
cv.wait(lck, [this] { return !q_.empty() || !running; });
if (!running){return {};} // tidy-up part 1
T t = q_.front();
q_.pop();
return t;
}
bool is_running()
{
return running;
}
void stop()
{
running = false;
cv.notify_all(); // tidy-up part 2
}
};
see live example: https://godbolt.org/z/bje6Gj7o4
Obviously needs tidying up as you require

Related

std::unique_lock move semantic

Please help me check if my understanding of std::unique_lock move semantic is correct.
Let's say I have a function myFunc which needs to acquire a mutex at the beginning of its execution.
This function is called from different functions, some of them e.g. myWrapper1 hold the same mutex before myFunc call.
Sometimes I need this lock not be released when myFunc's scope exits.
typedef std::unique_lock<std::mutex> MyLock;
class Example2
{
std::mutex m_data_mutex;
MyLock&& myFunc(MyLock&& lk)
{
bool was_lock = lk.owns_lock();
if( !was_lock ) lk.lock();
std::cout << "myFunc" << std::endl;
if( !was_lock ) lk.unlock();
return std::move(lk);
}
void myWrapper1()
{
MyLock lk(m_data_mutex);
std::cout << "1" << std::endl;
lk = myFunc(std::move(lk));
std::cout << "2" << std::endl;
}
void myWrapper2()
{
MyLock lk(m_data_mutex);
std::cout << "1" << std::endl;
lk.unlock();
lk = myFunc(std::move(lk));
std::cout << "2" << std::endl;
lk.lock();
std::cout << "3" << std::endl;
}
};
So the questions are:
for myWrapper1 there's a guarantee that MyLock will be released only at the end of myWrapper1 scope, isn't it?
Do I use a correct idiom for this problem?
Is there some reason why you can't do something like this instead? IMO, it's a lot more clean than moving locks around from owner to owner.
std::mutex my_lock;
void myFunc_locked() {
...do something that requires my_lock to be locked...
}
void myFunc() {
std::lock_guard<std::mutex> guard(my_lock);
myFunc_locked();
}
void myWrapper1() {
std::lock_guard<std::mutex> guard(my_lock);
...do something else that requires my_lock to be locked...
myFunc_locked();
}
void myWrapper2() {
...
myFunc();
}
Or, do as #Nevin suggested. Maybe cleaner still:
std::mutex my_lock;
void myFunc(std::lock_guard<std::mutex>> const& guard) {
...do something that requires my_lock to be locked...
}
void myFunc() {
std::lock_guard<std::mutex> guard(my_lock);
myFunc(guard);
}
void myWrapper1() {
std::lock_guard<std::mutex> guard(my_lock);
...do something else that requires my_lock to be locked...
myFunc(guard);
}
void myWrapper2() {
...
myFunc();
}

Is using std::future the best way to safely stop a thread?

I'm reading this tutorial on how to safely exit from threads.
In essence, it passes a future object to the function that is going to be executed from the thread, and checks, at every while loop, if that future already has a value (if it has, it exits the thread). See:
void threadFunction(std::future<void> futureObj)
{
std::cout << "Thread Start" << std::endl;
while (futureObj.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout)
{
std::cout << "Doing Some Work" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Thread End" << std::endl;
}
The problem is that in order to check if futureObj is already setted, it has to wait for some time (here, 1 millissecond). So, I'm losing 1 millissecond on every iteration of the thread. Shouldn't this be preferable:
void threadFunction(bool *shouldStop)
{
std::cout << "Thread Start" << std::endl;
while (!*shouldStop)
{
std::cout << "Doing Some Work" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
std::cout << "Thread End" << std::endl;
}
In order to check shouldStop, no time is wasted. So my thread runs faster. Why he didn't do that?
UPDATE:
Here's a simple class that should do the same thing, I guess.
class Stoppable
{
private:
std::atomic<bool> _shouldContinue;
public:
Stoppable()
{
_shouldContinue.store(true);
}
virtual void run() = 0;
void operator()()
{
run();
}
bool shouldContinue()
{
return _shouldContinue.load();
}
void stop()
{
_shouldContinue.store(false);
}
};
Then, to use it, just subclass Stoppable and do like this:
void MySubClass::run()
{
while (shouldContinue())
{
//...
}
}
The second proposal:
void threadFunction(bool *shouldStop)
Is I am afraid wrong if you intend to set *shouldStop from another thread.
In this case it should be void threadFunction(std::atomic<bool> *shouldStop).
There is no one "right way" to signal a thread to stop as it will depend on whether you want your thread to work continually or only work when there is work to do. But there are wrong ways - usually involving undefined behaviour because of writing to a non-atomic variable in one thread and reading from it in another.
If you want your thread to continually work until stopped (for example, this is common in graphics rendering threads or real-time game logic threads) then there is no reason to wait before checking your stop signal.
If your thread is a worker thread which will only run while there is work to do, then it's more normal to use a std::condition_variable, std::mutex and a queue plus a signal.
In case it's interesting, here's an example of an implementation of a work queue. Note that this one permits completion of the work out of order with respect to submission. There are many strategies available:
#include <condition_variable>
#include <mutex>
#include <queue>
#include <functional>
#include <thread>
#include <vector>
#include <iostream>
#include <iomanip>
struct worker_control
{
std::queue<std::function<void()>> work_queue;
std::mutex m;
std::condition_variable cv;
bool stop_signal = false;
void post_work(std::function<void()> f)
{
auto lock = std::unique_lock(m);
work_queue.push(std::move(f));
lock.unlock();
cv.notify_one();
}
void request_stop()
{
auto lock = std::unique_lock(m);
stop_signal = true;
lock.unlock();
cv.notify_all();
}
};
std::mutex emit_mutex;
template<class...Args>
void emit(Args&&...args)
{
auto lock = std::unique_lock(emit_mutex);
std::cout << std::this_thread::get_id() << " : ";
((std::cout << args), ...);
std::cout << '\n';
}
void run_worker(worker_control& control)
{
auto should_run = [&]
{
return not control.work_queue.empty() or control.stop_signal;
};
while (1)
{
auto lock = std::unique_lock(control.m);
control.cv.wait(lock, should_run);
// at this point we own the lock on control.m
if (not control.work_queue.empty())
{
auto work = std::move(control.work_queue.front());
control.work_queue.pop();
lock.unlock(); // allow other workers access to the queue
work();
}
else
{
// we can only have got here if there is no work to do and we have been asked to stop
return;
}
}
}
int main()
{
std::vector<std::thread> worker_threads;
auto control = worker_control();
worker_threads.emplace_back([&]{ run_worker(control); });
worker_threads.emplace_back([&]{ run_worker(control); });
worker_threads.emplace_back([&]{ run_worker(control); });
control.post_work([]{ emit("the"); });
control.post_work([]{ emit("quick"); });
control.post_work([]{ emit("brown"); });
control.post_work([]{ emit("fox"); });
control.post_work([]{ emit("jumps"); });
control.post_work([]{ emit("over"); });
control.post_work([]{ emit("the"); });
control.post_work([]{ emit("lazy"); });
control.post_work([]{ emit("dog"); });
control.request_stop();
for (auto& t : worker_threads)
if (t.joinable())
t.join();
}
Example output:
140244960823040 : the
140244960823040 : fox
140244960823040 : jumps
140244960823040 : over
140244960823040 : the
140244960823040 : lazy
140244960823040 : dog
140244969215744 : quick
140244952430336 : brown
https://coliru.stacked-crooked.com/a/c1612695a3cfc955

Thread safe std::cout

The following program still interleaves the output to std::cout. I tried to add a std::mutex to control access to std::cout via std::lock_guard, but it still interleaves.
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
std::mutex global_mtx{};
class Timer {
public:
Timer(size_t time, const std::function<void(void)>& f) : time{std::chrono::milliseconds{time}}, f{f} {}
~Timer() { wait_thread.join(); }
private:
void wait_then_call()
{
std::unique_lock<std::mutex> lck{mtx};
for(int i{10}; i > 0; --i) {
{
std::lock_guard<std::mutex>{global_mtx};
std::cout << "Thread " << wait_thread.get_id() << " countdown at: " << '\t' << i << std::endl;
}
cv.wait_for(lck, time / 10);
}
f();
}
std::mutex mtx;
std::condition_variable cv{};
std::chrono::milliseconds time;
std::function <void(void)> f;
std::thread wait_thread{[this]() {wait_then_call(); }};
};
int main()
{
auto f = []() {std::lock_guard<std::mutex>{global_mtx}; std::cout << "---------------- I waited to print! ----------------" << std::endl; };
Timer t1{3'000,f};
Timer t2{6'000,f};
Timer t3{2'000,f};
Timer t4{1'000,f};
}
Do I need to control access through a separate class or dedicated thread?
Your problem is here: std::lock_guard<std::mutex>{global_mtx}; creates a lock guard and immediately releases it. You need to create a variable to hold the lock, like std::lock_guard<std::mutex> lock{global_mtx};.
One way to prevent forgetting to name the lock is to make a lock object that you can use as an io manipulator:
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
std::mutex global_mtx{};
struct lockio
{
lockio(std::mutex& m) : lock_(m) {}
std::unique_lock<std::mutex> lock_;
};
std::ostream& operator<<(std::ostream& os, const lockio&) {
return os;
}
class Timer {
public:
Timer(size_t time, const std::function<void(void)>& f) : time{std::chrono::milliseconds{time}}, f{f} {}
~Timer() { wait_thread.join(); }
private:
void wait_then_call()
{
std::unique_lock<std::mutex> lck{mtx};
for(int i{10}; i > 0; --i) {
{
std::cout << lockio(global_mtx) << "Thread " << wait_thread.get_id() << " countdown at: " << '\t' << i << std::endl;
}
cv.wait_for(lck, time / 10);
}
f();
}
std::mutex mtx;
std::condition_variable cv{};
std::chrono::milliseconds time;
std::function <void(void)> f;
std::thread wait_thread{[this]() {wait_then_call(); }};
};
int main()
{
auto f = []() { std::cout << lockio(global_mtx) << "---------------- I waited to print! ----------------" << std::endl; };
Timer t1{3'000,f};
Timer t2{6'000,f};
Timer t3{2'000,f};
Timer t4{1'000,f};
}
Another (probably better) way is to create a little helper template function to wrap the protected operations:
#include <iostream>
#include <thread>
#include <condition_variable>
std::mutex global_mtx{};
template<class Mutex, class F>
decltype(auto) with_lock(Mutex &m, F &&f) {
std::lock_guard<Mutex> lock(m);
return f();
};
class Timer {
public:
Timer(size_t time, const std::function<void(void)> &f) : time{std::chrono::milliseconds{time}}, f{f} {}
~Timer() { wait_thread.join(); }
private:
void wait_then_call() {
std::unique_lock<std::mutex> lck{mtx};
for (int i{10}; i > 0; --i) {
with_lock(global_mtx, [&] {
std::cout << "Thread " << wait_thread.get_id() << " countdown at: " << '\t' << i << std::endl;
});
cv.wait_for(lck, time / 10);
}
f();
}
std::mutex mtx;
std::condition_variable cv{};
std::chrono::milliseconds time;
std::function<void(void)> f;
std::thread wait_thread{[this]() { wait_then_call(); }};
};
int main() {
auto f = []() {
with_lock(global_mtx, []
{
std::cout << "---------------- I waited to print! ----------------" << std::endl;
});
};
Timer t1{3'000, f};
Timer t2{6'000, f};
Timer t3{2'000, f};
Timer t4{1'000, f};
}
one more way:
#include <iostream>
#include <thread>
#include <condition_variable>
struct locked {
std::ostream& cout() const { return std::cout; }
std::ostream& cerr() const { return std::cerr; }
private:
static std::mutex& mutex() {
static std::mutex stdio_mutex;
return stdio_mutex;
}
std::unique_lock<std::mutex> lock_{mutex()};
};
class Timer {
public:
Timer(size_t time, const std::function<void(void)> &f) : time{std::chrono::milliseconds{time}}, f{f} {}
~Timer() { wait_thread.join(); }
private:
void wait_then_call() {
std::unique_lock<std::mutex> lck{mtx};
for (int i{10}; i > 0; --i) {
locked().cout() << "Thread " << wait_thread.get_id() << " countdown at: " << '\t' << i << std::endl;
cv.wait_for(lck, time / 10);
}
f();
}
std::mutex mtx;
std::condition_variable cv{};
std::chrono::milliseconds time;
std::function<void(void)> f;
std::thread wait_thread{[this]() { wait_then_call(); }};
};
int main() {
auto f = []() {
locked().cout() << "---------------- I waited to print! ----------------" << std::endl;
};
Timer t1{3'000, f};
Timer t2{6'000, f};
Timer t3{2'000, f};
Timer t4{1'000, f};
}
You create four Timer objects, each one having its own unique mutex object. So when t2 runs its thread, it locks its own mutex and it can because t1 locked a different mutex before beginning its loop.

Is try_lock() +unlock() valid way to check whether boost::interprocess::file_lock is locked?

I need to check whether a file is locked using boost::interprocess::file_lock. I produced this, but I'm worried what it's gonna do:
bool DataCache::isLocked() const {
bool res = lock_->try_lock();
if(res)
lock_->unlock();
return res;
}
Is it a good idea? Isn't there a way to check it without locking it?
While the other answer is the key to not introducing a race condition, there is no reason to drop exception safety and error-resilience that comes from using the proper RAII wrappers like std::lock_guard<> and std::unique_lock<>.
You'd want to write:
if (auto lk = try_to_lock(mx)) {
std::cout << "simple test\n";
} // automatically unlocks at scope exit
And you can. Here's my simple implementation:
template <typename Lockable>
std::unique_lock<Lockable> try_to_lock(Lockable& lockable) {
return std::unique_lock<Lockable> (lockable, std::try_to_lock);
}
Live On Coliru
#include <mutex>
#include <iostream>
int main() {
// demo
std::mutex mx;
if (auto lk = try_to_lock(mx)) {
std::cout << "simple test\n";
} // automatically unlocks at scope exit
if (auto lk = try_to_lock(mx)) {
std::cout << "yes\n";
if (auto lk = try_to_lock(mx)) {
std::cout << "oops?!\n"; // not reached
} else {
std::cout << "no recursive lock\n";
}
// but you can manipulate the lock if you insist:
lk.unlock();
if (auto lk = try_to_lock(mx)) {
std::cout << "now we can lock again\n";
} else {
std::cout << "oops?!\n"; // not reached
}
}
}
Prints:
simple test
yes
no recursive lock
now we can lock again
As this doesn't fit in a comment: You could create "interface functions" for tryLock and unlock externally.
e.g.:
bool DataCache::try_lock() const {
return lock_->try_lock();
}
void DataCache::unlock() const {
lock_->unlock();
}
Usage:
DataCache cache;
if(cache.try_lock())
{
cache.doSomething();
cache.unlock();
}
else
{
//....
}
I'm not sure if the const will work here. I just copied it from the question code.

Producer-Consumer: Lost Wake-up issue

I was trying to write code for Producer-Consumer problem. Below code works fine most of the time but stuck sometimes because of "Lost Wake-up" (i guess). I tried thread sleep() but it didn't work. What modification is needed to handle this case in my code? Is semaphore can be helpful here ? If yes, how will i implement them here ?
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
using namespace std;
int product = 0;
boost::mutex mutex;
boost::condition_variable cv;
boost::condition_variable pv;
bool done = false;
void consumer(){
while(done==false){
//cout << "start c" << endl
boost::mutex::scoped_lock lock(mutex);
cv.wait(lock);
//cout << "wakeup c" << endl;
if (done==false)
{
cout << product << endl;
//cout << "notify c" << endl;
pv.notify_one();
}
//cout << "end c" << endl;
}
}
void producer(){
for(int i=0;i<10;i++){
//cout << "start p" << endl;
boost::mutex::scoped_lock lock(mutex);
boost::this_thread::sleep(boost::posix_time::microseconds(50000));
++product;
//cout << "notify p" << endl;
cv.notify_one();
pv.wait(lock);
//cout << "wakeup p" << endl;
}
//cout << "end p" << endl;
cv.notify_one();
done = true;
}
int main()
{
int t = 1000;
while(t--){
/*
This is not perfect, and is prone to a subtle issue called the lost wakeup (for example, producer calls notify()
on the condition, but client hasn't really called wait() yet, then both will wait() indefinitely.)
*/
boost::thread consumerThread(&consumer);
boost::thread producerThread(&producer);
producerThread.join();
consumerThread.join();
done =false;
//cout << "process end" << endl;
}
cout << "done" << endl;
getchar();
return 0;
}
Yes, you want a way to know (in the consumer) that you "missed" a signal. A semaphore can help. There's more than one way to skin a cat, so here's my simple take on it (using just c++11 standard library features):
class semaphore
{
private:
std::mutex mtx;
std::condition_variable cv;
int count;
public:
semaphore(int count_ = 0) : count(count_) { }
void notify()
{
std::unique_lock<std::mutex> lck(mtx);
++count;
cv.notify_one();
}
void wait() { return wait([]{}); } // no-op action
template <typename F>
auto wait(F&& func = []{}) -> decltype(std::declval<F>()())
{
std::unique_lock<std::mutex> lck(mtx);
while(count == 0){
cv.wait(lck);
}
count--;
return func();
}
};
For convenience, I added a convenience wait() overload that takes a function to be executed under the lock. This makes it possible for the consumer to operate the 'semaphore' without ever manually operating the lock (and still get the value of product without data-races):
semaphore sem;
void consumer() {
do {
bool stop = false;
int received_product = sem.wait([&stop] { stop = done; return product; });
if (stop)
break;
std::cout << received_product << std::endl;
std::unique_lock<std::mutex> lock(processed_mutex);
processed_signal.notify_one();
} while(true);
}
A fully working demo: Live on Coliru:
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <cassert>
class semaphore
{
private:
std::mutex mtx;
std::condition_variable cv;
int count;
public:
semaphore(int count_ = 0) : count(count_) { }
void notify()
{
std::unique_lock<std::mutex> lck(mtx);
++count;
cv.notify_one();
}
void wait() { return wait([]{}); } // no-op action
template <typename F>
auto wait(F&& func = []{}) -> decltype(std::declval<F>()())
{
std::unique_lock<std::mutex> lck(mtx);
while(count == 0){
cv.wait(lck);
}
count--;
return func();
}
};
semaphore sem;
int product = 0;
std::mutex processed_mutex;
std::condition_variable processed_signal;
bool done = false;
void consumer(int check) {
do {
bool stop = false;
int received_product = sem.wait([&stop] { stop = done; return product; });
if (stop)
break;
std::cout << received_product << std::endl;
assert(++check == received_product);
std::unique_lock<std::mutex> lock(processed_mutex);
processed_signal.notify_one();
} while(true);
}
void producer() {
std::unique_lock<std::mutex> lock(processed_mutex);
for(int i = 0; i < 10; ++i) {
++product;
sem.notify();
processed_signal.wait(lock);
}
done = true;
sem.notify();
}
int main() {
int t = 1000;
while(t--) {
std::thread consumerThread(&consumer, product);
std::thread producerThread(&producer);
producerThread.join();
consumerThread.join();
done = false;
std::cout << "process end" << std::endl;
}
std::cout << "done" << std::endl;
}
You seems to ignore that the variable done is also a shared state, to the same extend as product. Which can lead to several races conditions. In your case, I see at least one scenario where consumerThread make no progress:
The loop execute has intended
consumer executes, and is waiting at cv.wait(lock);
producer has finished the for loop, and notify consumer and is preempted
consumer wakes up, read "done==false", output product, read done == false again, wait on the condition
producer set done to true and exit
consumer is stuck forever
To avoid these kind of issues you should be holding a lock when reading or writing done. Btw your implementation is quite sequential, ie the producer and the consumer can only process a single piece of data at the time...