I would like to synchronize different threads properly but so far I have only be able to write an inelegant solution. Can somebody kindly point out how I can improve the following code?
typedef void (*func)();
void thread(func func1, func func2, int& has_finished, int& id) {
has_finished--;
func1();
has_finished++;
while (has_finished != 0) std::cout << "thread " << id << " waiting\n";
std::cout << "thread" << id << "resuming\n";
func2();
}
int main() {
int has_finished(0), id_one(0), id_two(1);
std::thread t1(thread, fun, fun, std::ref(has_finished), std::ref(id_one));
std::thread t2(thread, fun, fun, std::ref(has_finished), std::ref(id_two));
t1.join();
t2.join();
};
The gist of the program is described by the function thread. The function is executed by two std::threads. The function accepts two long-running functions func1 and func2 and two references of ints as arguments. The threads should only invoke func2 after all threads exited func1. The argument has_finished is used to coordinate the different threads: Upon entering the function, has_arguments is zero. Then each std::thread decrements the value and invokes the long-running function func1. After having left func1, has_finished is incremented again. As long as this value is not at its original value of zero a thread waits. Then, each thread works on func2. The main function is shown at the end.
How can I coordinate the two threads better? I was thinking of using a std::mutex and std::condition_variable but could not figure out how to use them properly? Does somebody have any idea how I can improve the program?
Don't write this yourself. This kind of synchronization is known as a "latch" (or more generally a "barrier", and it's available through various libraries and through the C++ Concurrency TS. (It might also make it into C++20 in some form.)
For example, using a version from Boost:
#include <iostream>
#include <thread>
#include <boost/thread/latch.hpp>
void f(boost::latch& c) {
std::cout << "Doing work in round 1\n";
c.count_down_and_wait();
std::cout << "Doing work in round 2\n";
}
int main() {
boost::latch c(2);
std::thread t1(f, std::ref(c)), t2(f, std::ref(c));
t1.join();
t2.join();
}
The method you've chosen won't actually work and results in undefined behavior because of the race conditions. As you surmised, you need a condition variable.
Here is a Gate class demonstrating how to use a condition variable to implement a gate that waits for some number of threads to arrive at it before continuing:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <sstream>
#include <utility>
#include <cassert>
struct Gate {
public:
explicit Gate(unsigned int count = 2) : count_(count) { } // How many threads need to reach the gate before it unlocks
Gate(Gate const &) = delete;
void operator =(Gate const &) = delete;
void wait_for_gate();
private:
int count_;
::std::mutex count_mutex_;
::std::condition_variable count_gate_;
};
void Gate::wait_for_gate()
{
::std::unique_lock<::std::mutex> guard(count_mutex_);
assert(count > 0); // Count being 0 here indicates an irrecoverable programming error.
--count_;
count_gate_.wait(guard, [this](){ return this-> count_ <= 0; });
guard.unlock();
count_gate_.notify_all();
}
void f1()
{
::std::ostringstream msg;
msg << "In f1 with thread " << ::std::this_thread::get_id() << '\n';
::std::cout << msg.str();
}
void f2()
{
::std::ostringstream msg;
msg << "In f2 with thread " << ::std::this_thread::get_id() << '\n';
::std::cout << msg.str();
}
void thread_func(Gate &gate)
{
f1();
gate.wait_for_gate();
f2();
}
int main()
{
Gate gate;
::std::thread t1{thread_func, ::std::ref(gate)};
::std::thread t2{thread_func, ::std::ref(gate)};
t1.join();
t2.join();
}
Hopefully the structure of this code looks enough like your code that you can understand what's going on here. From reading your code, it seems like you're looking for all threads to execute func1, then func2. You do not want func2 running while any thread is executing func1.
That can be thought of as a gate where all the threads are waiting to arrive at the 'finished func1' location before moving on to run func2.
I tested this code on my own local version of compiler explorer.
The main disadvantage of the latch in the other answer is that it is not yet standard C++. My Gate class is a simple implementation of the latch class mentioned in the other answer, and it is standard C++.
The basic way a condition variable works is that it unlocks a mutex, waits for a notify, then locks that mutex and tests the condition. If the condition is true, it continues without unlocking the mutex. If the condition is false, it starts over again.
So, after the condition variable says the condition is true, you have to do whatever you need to do, then unlock the mutex and notify everybody that you've done it.
The mutex here is guarding the shared count variable. Whenever you have a shared value you should guard it with a mutex so that no thread can see that value in an inconsistent state. The condition is that threads can wait for that count to reach 0, indicating that all threads have decremented the count variable.
Related
I'm trying to solve the next problem:
There are two types of functions. The first type can execute from different threads simultaneously (for example - read data from container). The second one must block all threads inside first-type-function until some operation done (for example - change container).
I am sure this is an easy task, but I can't find a solution. Can anyone please help me?
This is simple example. I expect threads to stop output for 1 second every 3 seconds (I'm aware that this code is unsafe (cout from different threads), but it's just an simple example)
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
void f() {
// TODO: wait if g() locked this
cout << "Hello from thread " << this_thread::get_id() << endl;
this_thread::sleep_for(100ms);
}
void g() {
// TODO: some lock for f()
cout << "All threads must sleep at night" << endl;
this_thread::sleep_for(1000ms);
// TODO: unlock
}
int main() {
thread t1([]() { for (;;) f(); });
thread t2([]() { for (;;) f(); });
thread t3([]() { for (;;) f(); });
for (;;) {
this_thread::sleep_for(3000ms);
g();
}
return 0;
}
This is a common pattern best solved using reader/writer locks. In C++ you want to use std::shared_lock and imagine that f is a reader and g is a writer.
Declare variable:
std::shared_mutex mutex;
In f:
// Multiple threads can enter the shared lock (readers).
std::shared_lock lock(mutex);
In g:
// Only one thread can enter the unique lock (writers).
std::unique_lock lock(mutex);
In the code below, which I have tried to make minimially verifiable, runs fine and does what it should (print 1,2,3 in order no matter which order I pass in threads). However, if I change m1 to m2 in the line that I have commented in the function third, this code crashes with the message "terminated without an active exception". Why can't I use the same condition variable to lock on two different mutex's at the same time?
#include <functional>
#include <mutex>
#include <condition_variable>
#include <future>
#include <iostream>
void printFirst() {
cout << "1";
}
void printSecond() {
cout << "2";
}
void printThird() {
cout << "3";
}
struct test {
condition_variable c, c2;
int count = 0;
mutex m1,m2;
void first(function<void()> printFirst) {
printFirst();
count++;
c.notify_all();
}
void second(function<void()> printSecond) {
unique_lock<mutex> sL1(m1);
c.wait(sL1,[&]{return count>=1;});
printSecond();
count+=1;
c.notify_all();
}
void third(function<void()> printThird) {
unique_lock<mutex> sL2(m1); //If I make m1, m2, this code crashes
c.wait(sL2,[&]{return count>=2;});
printThird();
}
};
int main() {
test t;
function<void()> printFirstN =[&](){ t.first(printFirst);};
function<void()> printSecondN=[&](){ t.second(printSecond);};
function<void()> printThirdN=[&](){ t.third(printThird);};
std::thread t1(printFirstN);
std::thread t2( printThirdN);
std::thread t3( printSecondN);
t1.join();
t2.join();
t3.join();
}
You can't do it because the C++ standard says you can't.
33.5.3 Class condition_variable [thread.condition.condvar]
void wait(unique_lock& lock);
Requires: lock.owns_lock() is true and lock.mutex() is locked by the
calling thread, and either
(9.1) — no other thread is waiting on this
condition_variable object or
(9.2) — lock.mutex() returns the same
value for each of the lock arguments supplied by all concurrently
waiting (via wait, wait_for, or wait_until) threads.
The second clause imposes a requirement that all execution threads must have the same mutex locked, if they are also blocking on the condition variable.
(The above is for the wait method that takes no additional parameters, the same requirement is repeated for all overloads/variations, including the one that your code uses, which takes a predicate).
I have a function that must not be called from more than one thread at the same time. Can you suggest some elegant assert for this?
You can use a thin RAII wrapper around std::atomic<>:
namespace {
std::atomic<int> access_counter;
struct access_checker {
access_checker() { check = ++access_counter; }
access_checker( const access_checker & ) = delete;
~access_checker() { --access_counter; }
int check;
};
}
void foobar()
{
access_checker checker;
// assert than checker.check == 1 and react accordingly
...
}
it is simplified version for single use to show the idea and can be improved to use for multiple functions if necessary
Sounds like you need a mutex. Assuming you are using std::thread you can look at the coding example in the following link for specifically using std::mutex: http://www.cplusplus.com/reference/mutex/mutex/
// mutex example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
std::mutex mtx; // mutex for critical section
void print_block (int n, char c) {
// critical section (exclusive access to std::cout signaled by locking mtx):
mtx.lock();
for (int i=0; i<n; ++i) { std::cout << c; }
std::cout << '\n';
mtx.unlock();
}
int main ()
{
std::thread th1 (print_block,50,'*');
std::thread th2 (print_block,50,'$');
th1.join();
th2.join();
return 0;
}
In the above code print_block locks mtx, does what it needs to do, and then unlocks mtx. If print_block is called from two different threads, one thread will lock mtx first and the other thread will block on mtx.lock() and be force to wait until the other thread calls mtx.unlock(). This means only one thread can execute the code between mtx.lock() and mtx.unlock() (exclusive) at the same time.
This assumes by "at the same time" you mean at the same literal time. If you only want one thread to be able to call a function I would recommend looking into std::this_thread::get_id which will get you the id of the current thread. An assert could be as simple as storing the owning thread in owning_thread_id and then calling assert(owning_thread_id == std::this_thread::get_id()).
Consider the following example:
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <signal.h>
#include <thread>
void sleepy() {
usleep(1.0E15);
}
int main() {
std :: thread sleepy_thread(sleepy);
// Wake it up somehow...?
sleepy_thread.join();
}
Here we have a thread that just sleeps forever. I want to join it, without having to wait forever for it to spontaneously wake from usleep. Is there a way to tell it from the extern "hey man, wake up!", so that I can join it in a reasonable amount of time?
I am definitely not an expert on threads, so if possible don't assume anything.
No, it is not possible using the threads from the standard library.
One possible workaround is to use condition_variable::sleep_for along with a mutex and a boolean condition.
#include <mutex>
#include <thread>
#include <condition_variable>
std::mutex mymutex;
std::condition_variable mycond;
bool flag = false;
void sleepy() {
std::unique_lock<std::mutex> lock(mymutex);
mycond.wait_for( lock,
std::chrono::seconds(1000),
[]() { return flag; } );
}
int main()
{
std :: thread sleepy_thread(sleepy);
{
std::lock_guard<std::mutex> lock(mymutex);
flag = true;
mycond.notify_one();
}
sleepy_thread.join();
}
Alternatively, you can use the Boost.Thread library, which implements the interruption-point concept:
#include <boost/thread/thread.hpp>
void sleepy()
{
// this_thread::sleep_for is an interruption point.
boost::this_thread::sleep_for( boost::chrono::seconds(1000) );
}
int main()
{
boost::thread t( sleepy );
t.interrupt();
t.join();
}
Other answers are saying you can use a timed muted to accomplish this. I've put together a small class using a timed mutex to block the 'sleeping' threads, and release the mutex if you want to 'wake' them early. The standard library provides a function for timed_mutex called try_lock_for which will try to lock a mutex for a period of time, before continuing on anyway (and returning an indication of failure)
This can be encapsulated in a class, like the following implementation, which only allows a single call to wake waiting threads. It could also be improved by including a waitUntil function for waiting until a time series to correspond to the timed_mutex's other timed waiting function, try_lock_until but I will leave that as an exercise to the interested, since it seems a simple modification.
#include <iostream>
#include <mutex>
#include <thread>
#include <chrono>
#include <atomic>
// one use wakable sleeping class
class InterruptableSleeper{
std::timed_mutex
mut_;
std::atomic_bool
locked_; // track whether the mutex is locked
void lock(){ // lock mutex
mut_.lock();
locked_ = true;
}
void unlock(){ // unlock mutex
locked_ = false;
mut_.unlock();
}
public:
// lock on creation
InterruptableSleeper() {
lock();
}
// unlock on destruction, if wake was never called
~InterruptableSleeper(){
if(locked_){
unlock();
}
}
// called by any thread except the creator
// waits until wake is called or the specified time passes
template< class Rep, class Period >
void sleepFor(const std::chrono::duration<Rep,Period>& timeout_duration){
if(mut_.try_lock_for(timeout_duration)){
// if successfully locked,
// remove the lock
mut_.unlock();
}
}
// unblock any waiting threads, handling a situation
// where wake has already been called.
// should only be called by the creating thread
void wake(){
if(locked_){
unlock();
}
}
};
The following code:
void printTimeWaited(
InterruptableSleeper& sleeper,
const std::chrono::milliseconds& duration){
auto start = std::chrono::steady_clock::now();
std::cout << "Started sleep...";
sleeper.sleepFor(duration);
auto end = std::chrono::steady_clock::now();
std::cout
<< "Ended sleep after "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms.\n";
}
void compareTimes(unsigned int sleep, unsigned int waker){
std::cout << "Begin test: sleep for " << sleep << "ms, wakeup at " << waker << "ms\n";
InterruptableSleeper
sleeper;
std::thread
sleepy(&printTimeWaited, std::ref(sleeper), std::chrono::milliseconds{sleep});
std::this_thread::sleep_for(std::chrono::milliseconds{waker});
sleeper.wake();
sleepy.join();
std::cout << "End test\n";
}
int main(){
compareTimes(1000, 50);
compareTimes(50, 1000);
}
prints
Begin test: sleep for 1000ms, wakeup at 50ms
Started sleep...Ended sleep after 50ms.
End test
Begin test: sleep for 50ms, wakeup at 1000ms
Started sleep...Ended sleep after 50ms.
End test
Example & Use on Coliru
"Is there a way to tell it from the extern "hey man, wake up!", so that I can join it in a reasonable amount of time?"
No, there's no way to do so according c++ standard mechanisms.
Well, to get your thread being woken, you'll need a mechanism that leaves other threads in control of it. Besides usleep() is a deprecated POSIX function:
Issue 6
The DESCRIPTION is updated to avoid use of the term "must" for application requirements.
This function is marked obsolescent.
IEEE Std 1003.1-2001/Cor 2-2004, item XSH/TC2/D6/144 is applied, updating the DESCRIPTION from "process' signal mask" to "thread's signal mask", and adding a statement that the usleep() function need not be reentrant.
there's no way you could get control of another thread, that's going to call that function.
Same thing for any other sleep() functions even if declared from std::thread.
As mentioned in other answers or comments, you'll need to use a timeable synchronization mechanism like a std::timed_mutex or a std::condition_variable from your thread function.
Just use a semaphore, call sem_timedwait instead of usleep, and call sem_post before calling join
One possible approach:(There are many ways to accomplish..also its not good idea to use sleep in your thread)
///Define a mutex
void sleepy()
{
//try to take mutex lock which this thread will get if main thread leaves that
//usleep(1.0E15);
}
int main()
{
//Init the Mutex
//take mutex lock
std :: thread sleepy_thread(sleepy);
//Do your work
//unlock the mutex...This will enable the sleepy thread to run
sleepy_thread.join();
}
Sleep for a short amount of time and look to see if a variable has changed.
#include <atomic>
#include <unistd.h>
#include <thread>
std::atomic<int> sharedVar(1);
void sleepy()
{
while (sharedVar.load())
{
usleep(500);
}
}
int main()
{
std :: thread sleepy_thread(sleepy);
// wake up
sharedVar.store(0);
}
I'm trying to write a test (without examining the assembly code) to see whether a certain compiler is conformant with the thread-safe requirement of the c++11 standard about the initialization of static local objects.
So far I can only come up with non-deterministic approaches (sleeping for a long enough time on one thread to make it likely (but not surely, problem!) that the other thread has run to a certain point of execution).
Is there a way to do it deterministically?
E.g. a sync voodoo (see comments) like this:
#include <thread>
#include <mutex>
#include <chrono>
#include <iostream>
std::mutex g_mutex;
const std::chrono::seconds g_dura(1);
void log(const char* msg) {
std::clog << std::this_thread::get_id()
<< " " << msg
<< std::endl;
}
struct Asset {
Asset () {
log("before lock attempt");
g_mutex.lock();
log("after lock attempt");
/*EDIT*/g_mutex.unlock();
}
};
void test() {
log("entering test()");
static Asset asset;
log("leaving test()");
}
int main() {
g_mutex.lock();
std::thread t1(test), t2(test);
std::this_thread::sleep_for(g_dura);
// cleanup
g_mutex.unlock();
t1.join();
t2.join();
}
This lets the first thread (not necessarily t1), which has to do the init, wait in the ctor, and desired behaviour is, that the second (not necessarily t1) thread waits before the pending static variable init (in the first thread) is completed.
So there is just one pair of "before lock attempt"/"after lock attempt" messages printed if the compiler works correctly.
g++ (Debian 4.8.2-16) behaved well.
That voodoo can be put to the top if the t1,t2 themselves manage the control flow of the main thread; I skipped that and simply set a timer.