Consider this simple synchronization problem. I have two threads, A and B, that each execute 2 steps. I want step 1a to be performed before step 2b.
Thread A
Thread B
Step 1a
Step 1b
Step 2a
Step 2b
I have some options for how to implement this.
std::condition_variable + std::mutex + bool
This is the solution proposed by this stack overflow answer and this leetcode discussion page.
Thread B will wait on the condition variable, and Thread A will notify the condition variable. The mutex is required because it is the argument of the condition_variable's wait.
#include <iostream>
#include <thread>
#include <condition_variable>
std::condition_variable step_1a;
std::mutex a_mutex_I_guess;
bool step_1a_done = false;
void Step_1a() {
std::cout << "step 1a" << "\n";
}
void Step_2a() {
std::cout << "step 2a" << "\n";
}
void Step_1b() {
std::cout << "step 1b" << "\n";
}
void Step_2b() {
std::cout << "step 2b" << "\n";
}
void A() {
//std::unique_lock<std::mutex> lck{ a_mutex_I_guess }; unnecessary
Step_1a();
step_1a_done = true;
//lck.unlock(); unnecessary
step_1a.notify_one();
Step_2a();
}
void B() {
Step_1b();
std::unique_lock<std::mutex> lck{ a_mutex_I_guess };
step_1a.wait(lck, []() { return step_1a_done; });
Step_2b();
}
int main() {
std::thread thread_A{ A };
std::thread thread_B{ B };
thread_A.join();
thread_B.join();
}
To me, this seems like overkill. std::condition_variables are designed to handle multiple waiting threads. std::mutex is intended to protect shared data, not to be fodder for wait. On top of all of that, I needed bool step_1a_done to actually keep track of whether or not step_1a had completed.
As a measure of their complexity, the mutex, condition_variable, and bool together require 153 (80 + 72 + 1) bytes of memory on my machine.
std::binary_semaphore
Alternatively, I can use a binary semaphore. Semantically, the binary semaphore isn't meant for one-time-use. However, it gets the job done with simpler tools than the previous option.
#include <iostream>
#include <thread>
#include <semaphore>
std::binary_semaphore step_1a_sem{ 0 };
void Step_1a() {
std::cout << "step 1a" << "\n";
}
void Step_2a() {
std::cout << "step 2a" << "\n";
}
void Step_1b() {
std::cout << "step 1b" << "\n";
}
void Step_2b() {
std::cout << "step 2b" << "\n";
}
void A() {
//std::unique_lock<std::mutex> lck{ a_mutex_I_guess }; unnecessary
Step_1a();
step_1a_sem.release();
Step_2a();
}
void B() {
Step_1b();
step_1a_sem.acquire();
Step_2b();
}
int main() {
std::thread thread_A{ A };
std::thread thread_B{ B };
thread_A.join();
thread_B.join();
}
step_1a_sem requires only 1 byte of memory.
Question
My assessment is that binary_semaphore is better. However, even better would be a "one_time_semaphore" that documents (or enforces) in my code that release should only be called once. Are there C++ concurrency primitives that are a better fit for this thread synchronization problem?
EDIT: std::promise<void>
#Daniel Langr has pointed out that std::promise<void> also works. While this seems like the exact use case of std::promise<void>, things appear significantly more complicated under the hood than with a binary_semaphore. The memory requirement is 24 bytes.
#include <iostream>
#include <thread>
#include <future>
std::promise<void> step_1a_done;
void Step_1a() {
std::cout << "step 1a" << "\n";
}
void Step_2a() {
std::cout << "step 2a" << "\n";
}
void Step_1b() {
std::cout << "step 1b" << "\n";
}
void Step_2b() {
std::cout << "step 2b" << "\n";
}
void A() {
Step_1a();
step_1a_done.set_value();
Step_2a();
}
void B() {
Step_1b();
step_1a_done.get_future().wait();
Step_2b();
}
int main() {
std::thread thread_A{ A };
std::thread thread_B{ B };
thread_A.join();
thread_B.join();
}
Related
This is my minimal, reproducible example
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
#include <functional>
class BaseClass {
public:
void do_func() {
while(true) {
std::cout << "doing stuff" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
};
int main() {
auto obj = std::make_unique<BaseClass>();
std::thread t(&BaseClass::do_func, obj.get());
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "reset called!" << std::endl;
obj.reset();
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "going out of scope" << std::endl;
t.join();
return 0;
}
I was expecting the object to be deleted after reset is called. Even the code cannot exit because the while loop is blocking, which is understandable. I need to delete the object after a particular event, and cannot wait till the unique_ptr goes out of scope. If I change the do_func to
void do_func() {
std::cout << "doing stuff" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(20));
}
then it is the expected behaviour.
Edit:
Based on your comments I have updated my code to
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
#include <functional>
class BaseClass {
public:
BaseClass() : x(1) {
dummy = std::make_shared<SomeClass>();
}
void do_func() {
while(true) {
std::cout << "doing stuff " << dummy->do_stuff(x) << std::endl;
x++;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
private:
int x;
class SomeClass {
public:
int do_stuff(int x) {
return x * x;
}
};
std::shared_ptr<SomeClass> dummy;
};
int main() {
auto obj = std::make_unique<BaseClass>();
std::thread t(&BaseClass::do_func, obj.get());
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "reset called!" << std::endl;
obj.reset();
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "going out of scope" << std::endl;
t.join();
return 0;
}
And now the function does print garbage values. Does that mean I need to explicitly delete dummy in the destructor?
The simplest way to synchronize these two threads would be to use std::atomic_bool
#include <atomic>
class BaseClass {
public:
std::atomic_bool shouldContinueWork = true;
void do_func() {
while(shouldContinueWork) {
std::cout << "doing stuff" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
};
int main() {
auto obj = std::make_unique<BaseClass>();
std::thread t(&BaseClass::do_func, obj.get());
std::this_thread::sleep_for(std::chrono::seconds(5));
obj->shouldContinueWork = false; //the thread will not do anything more after this, but the sleep will need to end on it's own
std::cout << "stopping work!" << std::endl;
// do not remove the object before join is called - you don't know if it will be still accessed from the other thread or not
// obj.reset();
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "going out of scope" << std::endl;
t.join();
// here it is safe to remove the `obj`, main thread is surely the only thread that accesses it
// (but it goes out of scope anyway)
return 0;
}
This solution doesn't take into account stopping the work midway (i.e. whole loop iteration must always be performed) and is generally prone to having a few more or less iterations of work - it should be precise enough when you have sleep of 1s, but with smaller sleep it won't guarantee any exact number of iterations, take that into account. std::condition_variable can be used for more precise control of thread synchronization.
Thanks for all your quick responses! Let me know if this is a good solution
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
#include <functional>
class BaseClass {
public:
BaseClass() : x(1) {
dummy = std::make_shared<SomeClass>();
}
virtual ~BaseClass() {
dummy.reset();
}
void do_func() {
while(dummy) {
std::cout << "doing stuff " << dummy->do_stuff(x) << std::endl;
x++;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
private:
int x;
class SomeClass {
public:
int do_stuff(int x) {
return x * x;
}
};
std::shared_ptr<SomeClass> dummy;
};
class DerivedClass : public BaseClass {
};
int main() {
auto obj = std::make_unique<DerivedClass>();
std::thread t(&BaseClass::do_func, obj.get());
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "reset called!" << std::endl;
obj.reset();
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "going out of scope" << std::endl;
t.join();
return 0;
}
The behaviour is now as expected.
I have a main program, this main program executes a thread that perform an action until the user triggers a stop. The problem that I have is if I add th.join() the main program won't continue until the thread finishes. And If there is no .join() the program crashs.
#include <iostream>
#include <thread>
#include <optional>
static bool s_finished = false;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
//th1.join();
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording();
std::this_thread::sleep_for(5s);
stopRecording();
return 0;
}
How can I do this?
Joining a thread will cause the program to stop until that thread is finished, and that's why the program blocks. We have to call join() eventually so that all child threads finish before the program exits, but we shouldn't call join until we need the child thread to be finished.
The simplest way to get the program to work is to return the thread from startRecording, so that we have control of it inside main. Then, we join the thread at the end of main, after we call stopRecording.
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
std::thread startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
// (2) We return the thread so we can join it in main:
return th1;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
// (3) We save the thread to a variable named 'worker'
// so we can join it later. I also added an input to startRecording b/c it needed one
std::thread worker = startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
Now, the program prints the expected output, then exits without problems:
Start Program!
[startRecording] Other Task
Working thread: 1
Started thread id: 139985258444544
Working
Working
Working
Working
Working
[stopRecording] Other Task
I marked my changes with (1), (2), (3), and (4) in the comments of the code. They're pretty small, and if you have questions about any of them I can provide additional explanation!
Addendum - using global variables when the signature of startRecording can't be changed
In general, it's best to avoid global variables, but I know it's not always possible to do so. if startRecording's signature can't be changed, we can't return a thread, so the thread has to be accessed globally. Here's how to do that:
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
// (2) we initialize this in startRecording
std::thread worker;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
// (3) worker gets initialized, and thread starts
worker = std::thread(SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
This question already has answers here:
How do I terminate a thread in C++11?
(7 answers)
How to stop the thread execution in C++
(3 answers)
Proper way to terminate a thread in c++
(1 answer)
Closed 3 years ago.
My main function loads a monitoring class. This class calls external services to periodically get some data and report health status.
These are the task_1 and task_2 in the class below, that can have sub tasks. The tasks accumulate some values that are stored to a shared "Data" class.
So each task_N is coupled with a thread that executes, sleeps for a while and does this forever until the program stops.
My basic problem is that I cannot stop the threads in the Monitor class, since they might be waiting for the timer to expire (sleep)
#include <iostream>
#include <thread>
#include <utility>
#include "Settings.hpp"
#include "Data.hpp"
class Monitors {
public:
Monitors(uint32_t timeout1, uint32_t timeout2, Settings settings, std::shared_ptr<Data> data)
: timeout_1(timeout1), timeout_2(timeout2), settings_(std::move(settings)), data_(std::move(data)) {}
void start() {
thread_1 = std::thread(&Monitors::task_1, this);
thread_2 = std::thread(&Monitors::task_2, this);
started_ = true;
}
void stop() {
started_ = false;
thread_1.join();
thread_2.join();
std::cout << "stopping threads" << std::endl;
}
virtual ~Monitors() {
std::cout << "Monitor stops" << std::endl;
}
private:
void subtask_1_1() {
//std::cout << "subtask_1_1 reads " << settings_.getWeb1() << std::endl;
}
void subtask_1_2() {
//std::cout << "subtask_1_2" << std::endl;
data_->setValue1(21);
}
void task_1() {
while(started_) {
subtask_1_1();
subtask_1_2();
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_1));
std::cout << "task1 done" << std::endl;
}
}
void subtask_2_1() {
//std::cout << "subtask_2_1" << std::endl;
}
void subtask_2_2() {
//std::cout << "subtask_2_2" << std::endl;
}
void task_2() {
while(started_) {
subtask_2_1();
subtask_2_2();
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_2));
std::cout << "task2 done" << std::endl;
}
}
private:
bool started_ {false};
std::thread thread_1;
std::thread thread_2;
uint32_t timeout_1;
uint32_t timeout_2;
Settings settings_;
std::shared_ptr<Data> data_;
};
The main function is here:
auto data = std::make_shared<Data>(10,20);
Settings set("hello", "world");
Monitors mon(1000, 24000,set,data);
mon.start();
int count = 1;
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << data->getValue2() << " and count is " << count << std::endl;
count++;
if ( count == 10)
break;
}
std::cout << "now I am here" << std::endl;
mon.stop();
return 0;
Now when I call mon.stop() the main thread stops only when the timer exprires.
How can I gracefully call mon.stop() and interrupt and call the task_N?
UPDATE: Since I don't want to call std::terminate, which is the proper way to implement a monitor class in c++
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
I am playing around with some sockets, thread and mutexes. My question concerns threads and mutexes:
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
this->connectionList_mutex.unlock();
}
}`
The main function is running in one thread, while the addNewSocket is called by another thread. The problem is, that when addNewSocket is called once (by the second thread), the next unlock by thread 1 (main) will fail with a strange "signal SIGABRT". I have worked two days on this now, but i did not manage to get it fixed, sadly. I hope you can help me.
Edit: ConnectionHandler is a class, that has connectionList_mutex as a member.
Edit: Sometimes i also get this error: "Assertion failed: (ec == 0), function unlock, file /SourceCache/libcxx/libcxx-65.1/src/mutex.cpp, line 44." but it occurs randomly.
Edit: This is the whole class (Reduced to a minimum, should be context independant to a certain degree, but crashes when i put it right after a client connected, and works if i put it right after the start:
class ConnectionHandler{
public:
ConnectionHandler();
int addNewSocket();
private:
int main();
static void start(void * pThis);
std::mutex connectionList_mutex;
};
ConnectionHandler::ConnectionHandler(){
std::thread t(&this->start, this);
t.detach();
}
void ConnectionHandler::start(void * pThis){
ConnectionHandler *handlerThis;
handlerThis = (ConnectionHandler *)pThis;
handlerThis->main();
}
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
this->connectionList_mutex.unlock();
}
}
My guess is that your ConnectionHandler object is being destroyed somewhere. Also, you have defined ConnectionHandler::start in a silly way.
First, ConnectionHandler::start should be defined this way:
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
The C++11 ::std::thread class is perfectly capable of preserving the type of the function argument so there is no need to resort to void *.
Secondly, add in this code:
void ConnectionHandler::~ConnectionHandler(){
const void * const meptr = this;
this->connectionList_mutex.lock();
::std::cout << "ConnectionHandler being destroyed at " << meptr << ::std::endl;
this->connectionList_mutex.unlock();
}
And change the constructor to read:
ConnectionHandler::ConnectionHandler(){
const void * const meptr = this;
::std::cout << "ConnectionHandler being created at " << meptr << ::std::endl;
std::thread t(&this->start, this);
t.detach();
}
This will show you when the ConnectionHandler object is being destroyed. And my guess is that your code is destroying it while your detached thread is still running.
The meptr thing is because operator << has an overload for void * that prints out the pointer value. Printing out the pointer value for this will allow you to match up calls to the constructor and destructor if you're creating multiple ConnectionHandler objects.
Edit: Since it turned out I was correct, here is how I would recommend you write the play ConnectionHandler class:
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <mutex>
class ConnectionHandler {
public:
ConnectionHandler();
~ConnectionHandler();
ConnectionHandler(const ConnectionHandler &) = delete;
const ConnectionHandler &operator =(const ConnectionHandler &) = delete;
int addNewSocket();
private:
int main();
static void start(ConnectionHandler * pThis);
::std::mutex connectionList_mutex;
volatile ::std::atomic_bool thread_shutdown;
::std::thread thread;
};
ConnectionHandler::ConnectionHandler()
: thread_shutdown(false), thread(&this->start, this)
{
}
ConnectionHandler::~ConnectionHandler()
{
thread_shutdown.store(true);
thread.join();
}
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
int ConnectionHandler::addNewSocket(){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test1" << ::std::endl;
return 0;
}
int ConnectionHandler::main(){
while(!thread_shutdown.load()){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test2" << ::std::endl;
::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
}
return 0;
}