I'm trying to create four threads printing some message.
I'm facing some issue with synchronisation.
Here is what my main() looks like
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int count = 4;
int main (void)
{
pthread_t thread1, thread2, thread3, thread4;
pthread_create (&thread4, NULL, function4, NULL);
pthread_create (&thread3, NULL, function3, NULL);
pthread_create (&thread2, NULL, function2, NULL);
pthread_create (&thread1, NULL, function1, NULL);
pthread_join (thread1, NULL);
pthread_join (thread2, NULL);
pthread_join (thread3, NULL);
pthread_join (thread4, NULL);
return 0;
}
function1() prints Function 1, function2() prints Function 2 and so on.
Desired Output should be the following:
Function 1
Function 2
Function 3
Function 4
Actual Output:
Function 1
/* Infinitely runs (Deadlock maybe) */
Actual Question:
Can we use one single condition variable for Synchronization of two or more threads ? If so how ?
If not, how do I tackle this problem ?
Here is the definition of function(n)
void *function1 ()
{
while (1)
{
if (count == 4)
{
pthread_mutex_lock (&mutex);
printf("Function 1\n");
count --;
pthread_mutex_unlock (&mutex);
pthread_cond_signal (&cond);
return NULL;
}
else
pthread_cond_wait(&cond, &mutex);
}
return NULL;
}
void *function2 ()
{
while (1)
{
if (count == 3)
{
pthread_mutex_lock (&mutex);
printf("Function 2\n");
count--;
pthread_mutex_unlock (&mutex);
pthread_cond_signal (&cond);
return NULL;
}
else
pthread_cond_wait(&cond, &mutex);
}
return NULL;
}
void *function3 ()
{
while (1)
{
if(count == 2)
{
pthread_mutex_lock (&mutex);
printf("Function 3\n");
count--;
pthread_mutex_unlock (&mutex);
pthread_cond_signal (&cond);
return NULL;
}
else
pthread_cond_wait(&cond, &mutex);
}
return NULL;
}
void *function4 ()
{
while (1)
{
if(count == 1)
{
pthread_mutex_lock (&mutex);
printf("Function 4\n");
pthread_mutex_unlock (&mutex);
pthread_cond_signal (&cond);
return NULL;
}
else
pthread_cond_wait(&cond, &mutex);
}
return NULL;
}
After a more clear understanding, I have resolved this issue.
This is a case of race condition.
Things wrong with the code:
Use pthread_cond_broadcast instead ofpthread_cond_signal.
From the man pages
The pthread_cond_broadcast() function shall unblock all threads currently blocked on the specified condition variable cond.
The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond
Not acquiring a lock before checking for if (count == X), Need a
place a lock before that (since count is global/shared variable).
Not placing an unlock if the control goes to else. Since a lock
is already placed (earlier before else), you need to unlock
it.
If you fail to do so, other threads will try to lock a mutex,
that is already locked , leading to race conditions.
Function should be as follow
void *function1 ()
{
while (1)
{
/* Take a lock on the Mutex */
pthread_mutex_lock (&mutex);
if (4 == count)
{
printf("Function 1\n"); /* Perform your task */
count--;
/* Once operation on shared variable (count) is completed, release lock*/
pthread_mutex_unlock (&mutex);
/* Broadcast to other threads about completion of task */
pthread_cond_broadcast (&cond);
return NULL;
}
else
{
/* If count doesnt match, wait on the condition (wait for signal from other threads) */
pthread_cond_wait(&cond, &mutex);
/* Unlock the mutex, since it was locked earlier - else goes to deadlock */
pthread_mutex_unlock (&mutex);
}
}
return NULL;
}
Here is the complete working code.
The change required is simple:
instead of:
else
pthread_cond_wait(&cond, &mutex);
do this:
else {
pthread_mutex_lock (&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock (&mutex);
}
It works for me with these changes, but results in unpredictable behaviour without the changes.
Edit:
This above mentioned simple way still leaves a race condition and doesn't fix the signal vs broadcast problem. To avoid it, the code should be structured like the following:
pthread_mutex_lock (&mutex);
if (count == 4)
{
printf("Function 1\n");
count --;
pthread_mutex_unlock (&mutex);
pthread_cond_broadcast (&cond); // NOTE: broadcast, not signal!
return NULL;
}
else
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock (&mutex);
Note that pthread_cond_broadcast is necessary as you want to wake up all threads.
Related
So reading this topic, the common way to exit would be using a flag. My question is, how is the waiting handled? Say the thread is only to run every 30s, how would you wait those 30s properly?
Using sem_timedwait() isn't ideal as it relies on the system clock and any change to the clock can severely impact your application. This topic explains using condition variables instead. The problem is, it relies on a mutex. You can't safely use pthread_mutex_lock() and pthread_mutex_unlock() in a signal handler. So in terms of my example above of 30s, if you want to exit immediately, who is handling the mutex unlock?
My guess would be another thread that sole purpose is to check the exit flag and if true it would unlock the mutex. However, what is that thread like? Would it not be wasted resources to just sit there constantly checking a flag? Would you use sleep() and check every 1s for example?
I don't believe my guess is a good one. It seems very inefficient and I run into similar "how do I wait" type of question. I feel like I'm missing something, but my searching is leading to topics similar to what I linked where it talks about flags, but nothing on waiting.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
pthread_mutex_t my_mutex;
volatile sig_atomic_t exitRequested = 0;
void signal_handler(int signum) {
exitRequested = 1;
}
bool my_timedwait(pthread_mutex_t *mutex, int seconds) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_t cond;
pthread_cond_init(&cond, &attr);
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
int status = pthread_cond_timedwait(&cond, mutex, &ts);
if (status == 0) {
return false; // mutex unlocked
}
if ((status < 0) && (status != ETIMEDOUT)) {
// error, do something
return false;
}
return true; // timedout
}
void *exitThread(void *ptr) {
// constant check???
while (1) {
if (exitRequested) {
pthread_mutex_unlock(&my_mutex);
break;
}
}
}
void *myThread(void *ptr) {
while (1) {
// do work
printf("test\n");
// wait and check for exit (how?)
if (!my_timedwait(&my_mutex, 30)) {
// exiting
break;
}
}
}
int main(void) {
// init and setup signals
struct sigaction sa;
sa.sa_handler = signal_handler;
sigaction(SIGINT, &sa, NULL);
// init the mutex and lock it
pthread_mutex_init(&my_mutex, NULL);
pthread_mutex_lock(&my_mutex);
// start exit thread
pthread_t exitHandler;
pthread_create(&exitHandler, NULL, exitThread, NULL);
// start thread
pthread_t threadHandler;
pthread_create(&threadHandler, NULL, myThread, NULL);
// wait for thread to exit
pthread_join(threadHandler, NULL);
pthread_join(exitHandler, NULL);
return EXIT_SUCCESS;
}
The solution is simple. Instead of having the first thread block in pthread_join, block that thread waiting for signals. That will ensure that a SIGINT can be handled synchronously.
You need a global structure protected by a mutex. It should count the number of outstanding threads and whether or not a shutdown is requested.
When a thread finishes, have it acquire the mutex, decrement the number of outstanding threads and, if it's zero, send a SIGINT. The main thread can loop waiting for a signal. If it's from the thread count going to zero, let the process terminate. If it's from an external signal, set the shutdown flag, broadcast the condition variable, unlock the mutex, and continue waiting for the thread count to hit zero.
Here's a start:
pthread_mutex_t my_mutex; // protects shared state
pthread_cond_t my_cond; // allows threads to wait some time
bool exitRequested = 0; // protected by mutex
int threadsRunning = 0; // protected by mutex
pthread_t main_thread; // set in main
bool my_timedwait(int seconds)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += seconds;
pthread_mutex_lock (&my_mutex);
while (exitRequested == 0)
{
int status = pthread_cond_timedwait(&my_cond, &my_mutex, &ts);
if (status == ETIMEDOUT) // we waited as long as supposed to
break;
}
bool ret = ! exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret; // timedout
}
bool shuttingDown()
{
pthread_mutex_lock (&my_mutex);
bool ret = exitRequested;
pthread_mutex_unlock (&my_mutex);
return ret;
}
void requestShutdown()
{
// call from the main thread if a SIGINT is received
pthread_mutex_lock (&my_mutex);
exitRequested = 1;
pthread_cond_broadcast (&my_cond);
pthread_mutex_unlock (&my_mutex);
}
void threadDone()
{
// call when a thread is done
pthread_mutex_lock (&my_mutex);
if (--threadsRunning == 0)
pthread_kill(main_thread, SIGINT); // make the main thread end
pthread_mutex_unlock (&my_mutex);
}
I'm using c posix threads, and i've encountered a problem I don't quite understand and would like some fresh eyes to see what the problem could be.
In summary, I'm creating 3 threads which check some program state, signal that they are ready, and then wait for further signals. Meanwhile the thread that created these threads is waiting (pthread_cond_wait_) for each thread to signal that it has been setup. However it seems that the mutex is never unlocked once a wait has been signaled, causing the program the halt entirely.
This is the code for the main thread:
pthread_mutex_lock(&scenario->mutex);
if (scenario->flags.sinkThreadSetup == 0) {
pthread_create(&sinkT, NULL, sinkProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->sinkSetupCondition, &scenario->mutex);
}
if (scenario->flags.freeThreadSetup == 0) {
pthread_create(&freeT, NULL, freeWheelProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->freeSetupCondition, &scenario->mutex);
}
if (scenario->flags.blockThreadSetup == 0) {
pthread_create(&blockT, NULL, blockProblemHandler, (void *)scenario);
pthread_cond_wait(&scenario->blockSetupCondition, &scenario->mutex);
}
scenario->state = VECTORING;
pthread_mutex_unlock(&scenario->mutex);
// Start wheel threads
pthread_t wheelThreads[NUM_WHEELS];
scenario_wheel_t threadDataArr[NUM_WHEELS];
for (int i =0; i < NUM_WHEELS; i++) {
threadDataArr[i].scenario = scenario;
threadDataArr[i].wheel = &scenario->wheels[i];
pthread_create(&wheelThreads[i], NULL, wheel_start, (void *)&threadDataArr[i]);
}
pthread_mutex_lock(&scenario->mutex);
pthread_cond_wait(&scenario->scenarioComplete_condition, &scenario->mutex);
pthread_mutex_unlock(&scenario->mutex);
Here is the code for the problem handler threads:
void *sinkProblemHandler(void *args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.sinkThreadSetup == 0) {
scenario->flags.sinkThreadSetup = 1;
pthread_cond_signal(&scenario->sinkSetupCondition);
}
if (scenario->state != SINKING) {
pthread_cond_wait(&scenario->conditions.sinking_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("SINKHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
void *blockProblemHandler(void *args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.blockThreadSetup == 0) {
scenario->flags.blockThreadSetup = 1;
pthread_cond_signal(&scenario->blockSetupCondition);
}
if (scenario->state != BLOCKED) {
pthread_cond_wait(&scenario->conditions.blocked_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("BlockHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
void *freeWheelProblemHandler(void * args) {
scenario_t *scenario = (scenario_t *) args;
while(scenario->flags.terminate != 1) {
pthread_mutex_lock(&scenario->mutex);
if (scenario->state == SETUP && scenario->flags.freeThreadSetup == 0) {
scenario->flags.freeThreadSetup = 1;
pthread_cond_signal(&scenario->freeSetupCondition);
}
if (scenario->state != BLOCKED) {
pthread_cond_wait(&scenario->conditions.freeWheeling_condition, &scenario->mutex);
if (scenario->flags.terminate == 1) {
pthread_mutex_unlock(&scenario->mutex);
pthread_exit(NULL);
}
printf("FreeHandler: I'M HELPING!");
}
pthread_mutex_unlock(&scenario->mutex);
}
pthread_exit(NULL);
}
We can see here that the problem handler threads signal their respective setup condition, and then wait for a different condition (pthread_cond_wait),which should unlock the mutex.
My initial thought was that the problem handler threads were signaling before the main thread has started waiting, thus creating a deadlock. However after attaching to the program, this is not the case, as the program does:
1. Starts a problem thread
2. waits for the problem setup condition (unlocking mutex)
3. problem handler thread lock mutex.
3. problem handler thread then signals setup complete
4. problem handler thread then waits (supposedly unlocking mutex)
5. Program halts completely. (like the mutex has not been unlocked).
Any help would be greatly appreciated.
Thanks
Your worker threads roughly all have the form of
while(var) {
pthread_mutex_lock(&scenario->mutex);
// ...
pthread_mutex_unlock(&scenario->mutex);
}
that is mutex is locked immediately after it is unlocked. The main thread has a little chance to continue execution, as it cannot reacquire the mutex.
This is from man pthread_cond_signal:
The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().
So, at a bare minimum you can try pthread_yield() before reacquiring the mutex in the worker threads; and even better reduce the usage of mutex and / or introduce different mutexes to let different sections run in parallel.
I`m using 2 threads in my program, 1 to print even numbers and the other to print odd numbers sequentially. When I run the below code, the programs blocks after printing 0 and 1. Seems like a deadlock.
But if I move rc=pthread_mutex_lock(&mutex) to above the while statements in both PrintEvenNos() and PrintOddNos(), the output is sequential and complete (as desired).
Could someone explain why it fails in the first case and what is causing the deadlock?
#include<stdio.h>
#include<pthread.h>
pthread_t tid[2];
unsigned int shared_data = 0;
pthread_mutex_t mutex;
pthread_cond_t even,odd;
unsigned int rc;
void* PrintEvenNos(void*);
void* PrintOddNos(void*);
void main(void)
{
pthread_create(&tid[0],0,&PrintEvenNos,0);
pthread_create(&tid[1],0,&PrintOddNos,0);
sleep(3);
pthread_join(tid[0],NULL);
pthread_join(tid[1],NULL);
}
void* PrintEvenNos(void *ptr)
{
//rc = pthread_mutex_lock(&mutex); /*works when I uncomment here and comment the next mutex_lock */
while (shared_data <= 5)
{rc = pthread_mutex_lock(&mutex);
if(shared_data%2 == 0)
{ printf("t1.....................................Even:%d\n",shared_data);
shared_data++;
pthread_cond_signal(&odd);
rc=pthread_mutex_unlock(&mutex);
}
else
{
pthread_cond_wait(&even, &mutex);
}
}
rc=pthread_mutex_unlock(&mutex);
}
void* PrintOddNos(void* ptr1)
{
// rc = pthread_mutex_lock(&mutex); /*works when I uncomment here and comment the next mutex_lock */
while (shared_data <= 5)
{
rc = pthread_mutex_lock(&mutex);
if(shared_data%2 != 0)
{
printf("t2.....................................odd:%d\n",shared_data);
shared_data++;
pthread_cond_signal(&even);
rc=pthread_mutex_unlock(&mutex);
}
else
{
pthread_cond_wait(&odd, &mutex);
}
}
rc=pthread_mutex_unlock(&mutex);
}
Your program has undefined behavior because your thread that was waiting re-acquired the lock when returning from pthread_cond_wait and then calls pthread_mutex_lock again on a mutex that it already owns.
Mutexes are meant to be used as you indicate by your comment. This is exactly what pthread_cond_wait is made for: it releases the lock on entry and re-acquires it on return.
Also, remove the pthread_mutex_unlock from the if branch, it is wrong. Generally you should only have one pair of lock/unlock calls that mark your critical section.
Move the lock and unlock as you mentioned in your comment. As placed, your program has a race condition and thus undefined behavior. You cannot access data that may be modified by another thread without synchronization to preclude concurrent access.
I know there are many examples for my question. However, I want to understand why 1 program that I wrote works and other doesn't.
Here is what I have written.
void * even()
{
while(1)
{
pthread_mutex_lock(&lock);
if(count % 2 == 0)
{
printf("count %d\n",count);
pthread_cond_signal(&cond);
}
else
{
pthread_cond_wait(&cond,&lock);
}
count++;
pthread_mutex_unlock(&lock);
if(count >= 100) return NULL;
}
}
void * odd()
{
while(1)
{
pthread_mutex_lock(&lock);
if(count % 2 == 1)
{
printf("count %d\n",count);
pthread_cond_signal(&cond);
}
else
{
pthread_cond_wait(&cond,&lock);
}
count++;
pthread_mutex_unlock(&lock);
if(count >= 100) return NULL;
}
}
So the above piece of code prints only 0 or 0 and 1 sometimes. However the below code works fine.
void * even()
{
while(1)
{
pthread_mutex_lock(&lock);
if(count % 2 == 0)
{
printf("count %d\n",count);
count++;
pthread_cond_signal(&cond);
}
else
{
pthread_cond_wait(&cond,&lock);
}
pthread_mutex_unlock(&lock);
if(count >= 100) return NULL;
}
}
void * odd()
{
while(1)
{
pthread_mutex_lock(&lock);
if(count % 2 == 1)
{
printf("count %d\n",count);
count++;
pthread_cond_signal(&cond);
}
else
{
pthread_cond_wait(&cond,&lock);
}
pthread_mutex_unlock(&lock);
if(count >= 100) return NULL;
}
}
Thanks a lot.
In the first example, some variation of the below may happen:
even() acquires the lock
even() prints count (which is 0) and signals the condition (though odd() can't wake until even() releases the lock)
even() increments count to 1
even() releases the lock, and odd() wakes.
odd() increments count to 2
odd() releases the lock (but hasn't signalled the condition)
odd() acquires the lock
odd() waits, because count is even (== 2)... now both threads are waiting and neither can signal the condition.
Things may happen slightly differently depending on which thread goes first, but both threads still get stuck in a way similar to the above.
Both examples are unreliable, though, because they don't account for spurious wakeups when waiting for the condition. Normally a loop should be used to retry the wait if the desired wakeup conditions aren't met, holding the lock the whole time so a signal won't be missed:
pthread_mutex_lock(&lock);
/* ...stuff... */
/* Use a loop to restart the wait if it was interrupted early */
while(count % 2 != 0)
pthread_cond_wait(&cond,&lock);
/* ...stuff... */
pthread_mutex_unlock(&lock);
In the first example, in even(), then if count is odd, you pthread_cond_signal odd() to run if count is even. count will be incremented, and the mutex dropped. At this point odd() may run and signal even() before even() ever reaches the pthread_cond_wait(). Now odd() will never again signal even() (because count is now even), and the even()'s pthread_cond_wait() will never exit.
But both of your examples are buggy. You are (last full line) reading count outside the mutex that protects it.
#include <stdio.h>
#include <pthread.h>
#include<iostream>
void *odd(void* data);
void *even(void* data);
static int count=0;
pthread_mutex_t mutex;
pthread_cond_t cond;
int main()
{
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,&even,0);
pthread_create(&thread2,NULL,&odd,0);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
return 0;
}
void *even(void* data)
{
pthread_mutex_lock(&mutex);
while(count< 10)
{
while(count%2!=0)
{
pthread_cond_wait(&cond,&mutex);
}
std::cout<<count;
count++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
void *odd(void* data)
{
pthread_mutex_lock(&mutex);
while(count<10)
{
while(count%2!=1)
{
pthread_cond_wait(&cond,&mutex);
}
std::cout<<count;
count++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
I am currently learing all around POSIX threads (pthread).
I now have created a simple program which increased a shared value by 7 until above 10000 then it should signal a condition to the next thread which decreases it by 3 until under 1000. At last it should divide the result through 2 and main should output the result.
My code:
pthread_t threads[3];
pthread_cond_t cond_a, cond_b;
pthread_mutex_t mutex;
int counter;
void * worker_one();
void * worker_two();
void * worker_three();
int main(int argv, const char ** argc) {
counter = 0;
pthread_cond_init(&cond_a, NULL);
pthread_cond_init(&cond_b, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_create(&threads[0], NULL, worker_one, NULL);
pthread_create(&threads[1], NULL, worker_two, NULL);
pthread_create(&threads[2], NULL, worker_three, NULL);
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
pthread_join(threads[2], NULL);
printf("Value started at %d and ends with %d.\n", 0, counter);
return 0;
}
void * worker_one() {
printf("Worker one started.\n");
pthread_mutex_lock(&mutex);
printf("Worker one starting work.\n");
while (counter < 10000) {
counter += 7;
}
pthread_cond_signal(&cond_a);
printf("Worker one finished work with: %d.\n", counter);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void * worker_two() {
printf("Worker two started.\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_a, &mutex);
printf("Worker two starting work.\n");
while (counter > 1000)
counter -= 3;
printf("Worker two finished work with: %d.\n", counter);
pthread_cond_signal(&cond_b);
pthread_mutex_unlock(&mutex);
sleep(1);
pthread_exit(NULL);
}
void * worker_three() {
printf("Worker three started.\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_b, &mutex);
printf("Worker three starting work.\n");
counter /= 2;
printf("Worker three finished work with: %d.\n", counter);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
For some reason the whole execution hangs around the first thread. The signal is also fired but thread two does not react.
Can somebody tell me what I am doing wrong?
I have answered a similar question here: pthread condition variables on Linux, odd behaviour.
The problem is that you wait before even testing the condition you want to wait for is true.
What happens is that thread 1 signals before thread 2 is waiting, therefore the signal is lost and thread 2 will be waiting forever.
In order to avoid this, first test what you want to wait for, then wait only if it's not here.
EDIT: Ok, here is a possible solution with only one mutex and one condtion (untested)
Thread 1:
pthread_mutex_lock(&mutex);
while(thread_1_should_work == false){ // wait until the condition is satisfied
pthread_cond_wait(&cond, &mutex);
}
//at this point, we owe the mutex and we know thread_1_should_work is true;
// do work
thread_1_shoudl_work = false;
thread_2_should_work = true;
pthread_cond_broadcast(&cond); //wake up any waiting thread (if it's not their turn, they'll call wait again)
pthread_mutex_unlock(&mutex);
... and so on.