Using pthread_cond_t to signal end of execution - c

I am using pthread_cond_t to signal the end of execution of child threads to the main thread. Since I'm not synchronizing the access to a shared resource, I wonder what the loop embracing pthread_cond_wait would be? Here's what I have:
pthread_mutex_t mutex;
pthread_cond_t cond;
int main(int argc, char *argv[])
{
pthread_cond_init(&cond, NULL);
cond = PTHREAD_COND_INITIALIZER;
pthread_create(&tid1, NULL, func1, NULL);
pthread_create(&tid2, NULL, func2, NULL);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
//Join the thread that first completes
}
void *func1(void *arg)
{
....
pthread_cond_signal(&cond);
pthread_exit((void *) 1);
}
void *func2(void *arg)
{
....
pthread_cond_signal(&cond);
pthread_exit((void *) 1);
}
Would the main thread, by default, wait until thread1 or thread2 send it a signal or would we need some sort of a conditional loop around the wait?
Also, how would the main thread have access to the exit status of the thread that signaled without explicitly calling pthread_join? Or, is there a way to get the thread_id of the thread that signaled so that the main thread may join it to retrieve its exit status?

If both threads run to completion before the main thread reaches the pthread_cond_wait(), then it will wait forever. Otherwise, the main thread will wait until one of the other threads signals the condition.
No, you cannot ask the condition who signalled it.
Your pthread condition has no memory; if no thread is waiting on the condition when it is signalled, the signal is not remembered. What matters is the state you manage, protected by the mutex. The pthread condition is simply the mechanism which allows the thread to wait if the state requires it.
So, whatever information you need to pass from the child threads to the parent, the trick is to do that under the mutex. In this case you want to pass the fact that the child has finished. Perhaps a simple bool, so the main thread:
pthread_mutex_lock(&mutex) ;
while (!t1_done && !t2_done)
pthread_cond_wait(&cond, &mutex) ;
pthread_mutex_unlock(&mutex) ;
And thread the first:
pthread_mutex_lock(&mutex) ;
t1_done = true ;
pthread_cond_signal(&cond) ;
pthread_mutex_unlock(&mutex) ;
...all pretty straightforward, really.

Related

why this code return unexpected result? (conditional variable)

I am studying mutex lock.
so, I written test code about mutex lock.
but this code has a problem.
I want to show :
downloading.....
complete....
start play!
but at runtime, the result is :
downloading.....
complete....
I wnat know
1. why this code has error?
2. how to fix this code?
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int buffer = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* download(void *arg){
printf("downloading.....\n");
pthread_mutex_lock(&lock);
sleep(3);
buffer = 10;
printf("complete....\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
return NULL;
}
void* play(void *arg){
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock);
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(){
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, play, NULL);
pthread_create(&tid2, NULL, download, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
The download() function happens to run first, acquire the mutex and do all of its work (including calling pthread-cond_signal() before releasing the mutex.
The play() thread has no opportunity to call pthread_cond_wait() before the signal is sent because download() happened to acquire the mutex first. So when play() gets an opportunity to wait, it has already missed the signal that would wake it up.
The fix is to use the condition variable in conjunction with a flag (possibly buffer - depending on what you want to actually do). Several things need to be done with the flag:
the flag must be checked before calling pthread_cond_wait(), and if the flag indicates the condition is already met the wait should not be done
the "check flag/wait only if condition is not met yet" operations should be performed in a loop because pthread_cond_wait() can return spuriously (ie., without a signal having been made)
the flag check and any updates to the flag (in whatever thread) must be done while holding the mutex
Something like (the following code is untested):
void* play(void *arg)
{
pthread_mutex_lock(&lock);
while (buffer < 1) {
pthread_cond_wait(&cond, &lock);
}
printf("start play!\n");
--buffer;
pthread_mutex_unlock(&lock);
return NULL;
}

About threads and condition variable and synchronise

i am trying to understand the condition variables in thread programming can anyone explain how it works with the mutex and what are the condition variable so it can synchronise threads??
condition variables and threads
Here you go. Here I am using 3 mutexs and 3 condition variables. With the below examples you can schedule or control any number of threads in C. First look at the first thread below. Here it locked mutex lock1 (so that other thread could not access the codes) starts executing (codes not added just comments) and finally after completing its task waiting on cond1, likewise second thread locked mutex lock2, starts executing its business logic and finally waits on condition cond2 and 3rd thread locked mutex lock3, starts executing its business logic and finally waits on condition cond3. I am not adding any business logic here because this is just an example. In the commented section you can add your business logic which will execute in parallel mode. Suppose thread3 depends on final output of thread1 which is going to be inserted in a table and thread3 will read that information before creating it final result and thread2 depends on final outcome of thread3 to generate its final outcome. Hence thread1 after inserting the data into table, signals thread3 through condition variable to go ahead with its final process. That means thread1 controls thread3. As thread2 depends on final outcome from thread3, hence thread3 controls the execution of Thread2. Here we can allow thread1 to execute independently as its operation does not depends on any other thread, but for example of thread control we are controlling all the threads here and hence thread1 is being controlled from thread2.
To start the controlling process, we are releasing thread1 first. In the main thread (i.e. main function, every program has one main thread, in C/C++ this main thread is created automatically by operating system once the control pass to the main method/function by kernel) we are calling pthread_cond_signal(&cond1); Once this function called from main thread, thread1 which was waiting on cond1 will be released and it will start executing further. Once it finishes with its final task, it will call pthread_cond_signal(&cond3); now thread which was waiting on condition cond3 i.e. thread3 will be released and it will start to execute it’s final stage and will call pthread_cond_signal(&cond2); and it will release the thread which is waiting on condition cond2 i.e. in this case thread2. This is the way we can schedule and control execution of thread in multi-threaded environment.
#include<pthread.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond1, &lock1);
printf("I am thread1 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond2, &lock2);
printf("I am thread2 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond3, &lock3);
printf("I am thread3 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
sleep(1);
TRUE = 0;/* Stop all the thread */
sleep(3);
/* this is how we join thread before exit from a system */
/*
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);*/
exit(0);
}

Which thread would be notified by pthread_cond_signal?

When a thread call pthread_cond_signal(), Unix network programming said pthread_cond_signal() just would nofity just one thread, beacause it isn't pthread_cond_broadcast(). It means there is no race condition. However, the book does not say which thread would be notified, and how. Does the function wake thread randomly?
Straight from the man:
If more than one thread is blocked on a condition variable, the scheduling policy shall determine the order in which threads are unblocked.
The "scheduling policy" is the order the operating systems decided on. It's one of the four listed in the below link, but you don't really know (without some impressive hackery at least) which one is "first" anyway. It shouldn't matter either - all threads waiting on the condition should be equally ready to continue - otherwise you have a design problem.
Scheduling policies in Linux Kernel has a bit of discussion on some linux policies, and you can google from there if it's important.
See below my example which will help you to understand about it very clearly.I am using 3 mutexs and 3 conditions. With the below example you can synchronized or prioritize any number of threads in C. If you see the first thread here it locked mutex lock1 and waiting on cond1, likewise second thread locked mutex lock2 and waits on condition cond2 and 3rd thread locked mutex lock3 and waits on condition cond3. This is the current situation of all the threads after they are being created and now all the threads are waiting for a signal to execute further on its condition variable. In the main thread (i.e. main function, every program has one main thread, in C/C++ this main thread created automatically by operating system once control pass to the main method by kernal) we are calling pthread_cond_signal(&cond1); once this system call done thread1 who was waiting on cond1 will be release and it will start executing. Once it finished with its task it will call pthread_cond_signal(&cond3); now thread who was waiting on condition cond3 i.e. thread3 will be release and it will start execute and will call pthread_cond_signal(&cond2); which will release the thread who is waiting on condition cond2 i.e. in this case thread2.
include<pthread.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void print(char *p)
{
printf("%s",p);
}
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
pthread_cond_wait(&cond1, &lock1);
print("I am thread 1st\n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
pthread_cond_wait(&cond2, &lock2);
print("I am thread 2nd\n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
pthread_cond_wait(&cond3, &lock3);
print("I am thread 3rd\n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
sleep(1);
TRUE = 0;/* Stop all the thread */
sleep(3);
/* this is how we join thread before exit from a system */
/*
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);*/
exit(0);
}
Yes, it will wake one thread seemingly randomly. It's up to the operating system to decide which one will be woken.

pthread_mutex_lock why not block the thread as usual

Recently I read some code about thread mutex, releated code is here:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_t thread;
void fn(void *arg)
{
3 pthread_mutex_lock(&mutex);
printf( "signal before\n" );
4 pthread_cond_signal(&cond);
printf( "signal after\n" );
pthread_mutex_unlock(&mutex);
}
int main()
{
int err1;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond,NULL);
1 pthread_mutex_lock(&mutex);
2 err1 = pthread_create(&thread, NULL, fn, NULL);
usleep(1);
pthread_cond_wait(&cond,&mutex);
printf( "main thread get signal\n");
pthread_mutex_unlock(&mutex);
pthread_join(thread, NULL);
pthread_mutex_destroy( &mutex );
pthread_cond_destroy( &cond );
}
In main thread, first I call pthread_mutex_lock function locks the mutex in num 1, after I create a child thread in num 2, and in the child thread start function void fn( void *arg) I call pthread_mutex_lock in num 3 again, In theory it should block until mutex (main thread) is freed, but why can it continue to execute code in num 4 in child thread ?
execute result:
gcc version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Thanks very much.
The purpose of a condition variable is to permit threads to wait for things to happen in other threads. The problem with doing this with a mutex is that the following code doesn't work:
Acquire the lock that protects the shared state.
See if we need to wait, if so wait.
Oops. Now we're waiting while we hold the lock. So no other thread can change the shared state. So we'll wait forever. Let's try it again, this time releasing the lock:
Acquire the lock that protects the shared state.
If we need to wait, release the lock and wait.
Oops, we still have a problem. What if the thing we're waiting for happens after we release the lock but before we begin waiting? Again, we'll wait forever.
So we need an atomic "unlock and wait" function to make step 2 work. That's what pthread_cond_wait is. So the mutex is released while the thread is waiting.
The canonical use of pthread_cond_wait is:
pthread_mutex_lock(&mutex);
while (we_need_to_wait)
pthread_cond_wait(&cond, &mutex);
// possibly do some stuff while we still hold the mutex
pthread_mutex_unlock(&mutex);
Notice this allows us to decide to wait while we still hold the mutex, wait without holding the mutex, but have no window for a race condition where the mutex is released but we're not yet waiting.
By the way, it's extremely difficult to use a condition variable sanely any other way. So you really shouldn't attempt to use pthread_cond_wait in any other pattern until you have a rock solid understanding of how condition variables work. Make absolutely sure you always know precisely what you're waiting for and the thing you're waiting for is protected by the mutex that you pass to pthread_cond_wait.

pthreads: cancel blocking thread

I have a situation like
-Thread A-
Lock Mutex
If ActionA() == ERROR
Stop = True
Unlock Mutex
-Mainthread-
Lock Mutex
If ActionB() == ERROR
Stop = True
If Stop == True
Cancel ThreadA
Join ThreadA
Exit program
Unlock Mutex
where a Mutex is used for synchronization. The worker thread 'Thread A' and the main thread can both get into an error state and set the local variable 'Stop' then, which should lead to the cancellation of Thread A and exit of the main program. The Mutex is used to prevent a race condition when accessing Stop (and other shared objects).
Unfortunately calling pthread_cancel() does not seem to work when the target thread is waiting for a Mutex:
#include <pthread.h>
pthread_mutex_t mutex;
void *thread(void *args){
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock(&mutex);
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
pthread_t t;
pthread_create(&t, NULL, thread, NULL);
pthread_cancel(t);
pthread_join(t, NULL);
//Execution does not get here
}
Do you have any idea what I might try else?
Thank you in advance
pthread_mutex_lock() is just plain not a cancellation point where pthread_cancel() can cancel the thread; if you really need to break the thread, you need to find a way to release the mutex it's waiting for so it can reach a cancellation point (or, well, not use mutexes in the regions where it needs to be cancelled).
From the pthread_cancel() manual;
pthread_mutex_lock() is not a cancellation point, although it may block indefinitely; making pthread_mutex_lock() a cancellation point would make writing correct cancellation handlers difficult, if not impossible.

Resources