Reputation: 57
I have currently 2 pthreads running and I would like to wait for one of them to end for my program to continue.
In my pthreads I have a variable which can be true or false (it is a global variable). After creating the thread (one asking for a input in a cin and one waiting 10 seconds and if it reach 10 sec it kill the "cin" thread and end itself, the "cin" thread kill the "timer" thread if there is cin detected) I would like for my program to wait. When each of the thread end they put a variable "stoptimer" to true.
First after creating the threads I started writing a while loop like this :
while(stoptimer==false){}
The threads start, we enter into the while loop but even when the threads end and "stoptimer" goes to true we don't exit the loop.
I am currently doing this :
rc = pthread_create(&threads[1], NULL, Timer, (void *)&td[1]);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
rc = pthread_create(&threads[2], NULL, Choix, (void *)&i);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
while (stoptimer==false) {
cout<<"wait"<<endl;
}
Here you can see I am creating the threads and then entering the while loop with something in it. If I keep this loop as it is it is doing what I want, when the timer end or the user input a value we quit the while because "stoptimer" is no more false. But I don't want this cout to be here.
I tried putting a comment inside the loop in order for it to not be empty but it still react as being empty. In my understanding if it worked with the count then now it should work but simply do nothing.
Why is it doing this? Is there something special about empty while loop?
Upvotes: 2
Views: 1495
Reputation: 9991
The problem is not the while loop. The problem is that you have a race condition which is undefined behavior. Specifically it is not allowed to read and write a variable from different threads at the same time (R/R is ok, R/W and W/W are not). The compiler is free to "optimize" the while loop by caching the value of stoptimer
in a register and read from the register instead of the variable. Therefore it doesn't figure out that the value changed. The compiler is allowed to do this because it is illegal that stoptimer
changes while it is being read in the while-loop.
To fix the problem you need to lock a mutex before reading and writing shared variables. So you would do something like this:
while(true){
pthread_mutex_lock(stoptimer_mutex);
auto ts = stoptimer;
pthread_mutex_unlock(stoptimer_mutex);
if (ts==false)
break;
}
Now this is really long and tedious and you don't really want to do this every time you access stoptimer
. To get rid of all the manual locking you can use a atomic<bool> stoptimer
that does the locking and unlocking implicitly, exception safe and more efficiently. But it is still not good, because you have a busy wait. Now that you (hopefully) abandoned pthreads we can do the thread creation with standard library functions.
std::promise one_thread_done;
auto one_thread_future = one_thread_done.get_future();
std::thread timer_thread{Timer, td[1]}; //create threads
std::thread choix_thread{Choix, i};
one_thread_future.wait(); //wait until one of them is done
Inside each thread functions you put one_thread_done.set_value();
to signal that it has finished inside a try/catch, because it throws a future_error
if it has already been set by the other thread.
The upside of future
s is that they are easy to use and understand. The downside is that they are 1 use only, there is no resetting of future
s. If you need to repeatedly wait for one of the threads you will need a condition variable.
Upvotes: 2
Reputation: 62472
The issue here is that you're reading the stoptimer
variable without any form of thread synchronization, and I suspect you're writing to it without any, either.
In order for changes made by one thread to be guaranteed to be visible on another thread you've got to use some form of thread synchronization, or rely on knowing the memory model (weak or strong) of your underlying cpu, which often looks easy but can be difficult to get right at the best of times.
Looking at your code I suspect it would make more sensible to use a conditional variable to synchronize across threads.
Upvotes: 4