Story
According to the man page https://linux.die.net/man/3/pthread_mutex_lock
The mutex object referenced by mutex shall be locked by calling pthread_mutex_lock(). If the mutex is already locked, the calling thread shall block until the mutex becomes available.
I have a program with a thread. Here is the program flow:
The main process and the thread always call pthread_mutex_lock inside of a loop.
When the main process is holding the lock, the thread which is asking for lock, blocks (waiting for lock to be granted).
When the main process releases the lock with pthread_mutex_unlock, the thread should suddenly get the lock.
When the main process asks for the lock again, the main process should wait for the thread to release the lock.
The problem is that, at point 3, the thread does not suddenly get the lock as soon as the main process releases the lock. The main process gets it first when it calls to pthread_mutex_lock in the next loop cycle (at point 4).
How to deal with this situation?
Question
How can I make the thread get the lock as soon as the main process releases the lock?
Simple code to reproduce the problem
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t my_mutex = PTHREAD_MUTEX_INITIALIZER;
void *
my_thread(void *p)
{
(void)p;
while (1) {
pthread_mutex_lock(&my_mutex);
printf("The thread is holding the lock...\n");
sleep(1);
pthread_mutex_unlock(&my_mutex);
}
}
int
main()
{
pthread_t t;
pthread_create(&t, NULL, my_thread, NULL);
pthread_detach(t);
while (1) {
pthread_mutex_lock(&my_mutex);
printf("The main process is holding the lock...\n");
sleep(1);
pthread_mutex_unlock(&my_mutex);
}
}
Compile and Run
gcc test.c -o test -lpthread
./test
Expected result
The main process is holding the lock...
The thread is holding the lock...
The main process is holding the lock...
The thread is holding the lock...
The main process is holding the lock...
The thread is holding the lock...
The main process is holding the lock...
...
Actual result
The main process is holding the lock...
The main process is holding the lock...
The main process is holding the lock...
The main process is holding the lock...
The main process is holding the lock...
The main process is holding the lock...
The main process is holding the lock...
...
Calls story in order
main -> [1] call lock (get the lock)
thread -> [2] call lock (waiting for main to unlock)
main -> [3] call unlock
thread -> [4] (still does not get the lock from [2], why? even though it has been unlocked?)
main -> [5] lock (get the lock again)
thread -> [6] (still does not get the lock from [2])
main -> [7] call unlock
thread -> [8] (still does not get the lock from [2], why? even though it has been unlocked?)
main -> [9] lock (get the lock again)
... and so on ...
Summary
pthread_mutex_lock does not guarantee the order of lock requests.
pthread_mutex_lock guarantees that it will lock until the mutex becomes available. That does not mean that each lock() call enters a queue and is guaranteed to get the mutex lock next. It only means that nobody else will have the lock at the same time.
If you require a certain order, an option would be to use condition variables. That way, you can have a flag that is set to the next member which should get the mutex. You can then wait for the mutex until the value is as expected. See https://linux.die.net/man/3/pthread_cond_wait.
Alternatively, if your example has sleeps in it anyway as above, you can just move the sleep after the unlock() call. While that is not strictly speaking a guarantee, it will most definitely do the trick for a simple test. I do not recommend this approach for anything more serious/complex though.
EDIT: As Shawn correctly added, you can also use pthread_yield (1) to allow another thread to acquire the mutex if you don't care which other thread it is. Some intricacies with yielding are described in sched_yield(2).
PS: I would comment, but my rep is now high enough yet :)
Here is a 'fairlock' as an example; you can do better:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct fairlock FairLock;
struct fairlock {
pthread_mutex_t lock;
pthread_cond_t cv;
long scount;
long wcount;
};
#define err(x,v) do { int t; if ((t=(x)) != (v)) { \
error(__FILE__,__LINE__, #x, t, (v)); \
}} while (0)
static void error(char *fn, int lno, char *s, long x, long v) {
fprintf(stderr, "%s:%d %s returned %ld rather than %ld\n",
fn, lno, s, x, v);
exit(1);
}
void Lock(FairLock *f) {
err(pthread_mutex_lock(&f->lock), 0);
long me = f->scount++;
while (f->wcount != me) {
err(pthread_cond_wait(&f->cv, &f->lock), 0);
}
err(pthread_mutex_unlock(&f->lock), 0);
}
void UnLock(FairLock *f) {
err(pthread_mutex_lock(&f->lock), 0);
if (f->scount > f->wcount) {
f->wcount++;
err(pthread_cond_broadcast(&f->cv), 0);
}
err(pthread_mutex_unlock(&f->lock), 0);
}
FairLock *NewLock(void) {
FairLock *p = malloc(sizeof *p);
if (p != 0) {
err(pthread_mutex_init(&p->lock, 0),0);
err(pthread_cond_init(&p->cv, 0),0);
p->scount = p->wcount = 0;
}
return p;
}
void DoneLock(FairLock *f) {
err(pthread_mutex_destroy(&f->lock), 0);
err(pthread_cond_destroy(&f->cv), 0);
}
And your testlock.c changed to utilize it; again there is room for improvement, but you should be able to stick sleeps just about anywhere and it will remain fair....
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "fairlock.c"
FairLock *my;
void *
my_thread(void *p)
{
while (1) {
Lock(my);
printf("%s is holding the lock...\n", p);
UnLock(my);
}
}
int
main()
{
pthread_t t;
my = NewLock();
pthread_create(&t, NULL, my_thread, "one");
pthread_detach(t);
pthread_create(&t, NULL, my_thread, "two");
pthread_detach(t);
pthread_create(&t, NULL, my_thread, "three");
pthread_detach(t);
pthread_create(&t, NULL, my_thread, "four");
pthread_detach(t);
pthread_create(&t, NULL, my_thread, "five");
pthread_detach(t);
while (1) {
Lock(my);
printf("main process is holding the lock...\n");
UnLock(my);
}
}
TLDR Version:
The very next thing that either of your two loops does after releasing the lock is to try to acquire it again.
When there's a race between thread A which has just released a lock and thread B which has been blocked, waiting for the lock, thread A almost always will win because thread A already is running, and thread B still is "asleep."
Releasing the lock doesn't instantaneously "wake up" the waiting thread. All it does is change the status of the other thread from "waiting for the lock" to "waiting to be assigned a CPU to run on." Some time real soon after, the Scheduler will get around to restoring the context of thread B on another CPU, and thread B will start running, but by then it will be too late. Thread A will have already re-locked the lock.
Related
I'm trying to update a global variable in the main function and have a thread tell me when this variable is positive.
The code: https://pastebin.com/r4DUHaUV
When I run it, only 2 shows up though 1 and 2 should be the correct answer.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_t tid;
pthread_mutex_t mtx;
pthread_cond_t cond;
int nr=0;
void* function(void* arg)
{
pthread_mutex_lock(&mtx);
printf("Number in thread : %d \n",nr);
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
}
int main()
{
pthread_mutex_init(&mtx,NULL);
pthread_create(&tid,NULL,function,NULL);
int i;
for(i=0;i<3;i++)
{
int isPos=0;
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
if(nr>0)
isPos=1;
if(isPos==1)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
}
pthread_join(tid,NULL);
return 0;
}
As I mentioned in general comment, I'll repeat here:
There is no guarantee the main thread won't go off, locking the mutex,
changing nr, signaling the cv (whether or not anyone is actually
waiting on it), and unlocking the mutex, all before the child thread
even locks the mutex, much less starts waiting on the cv. In that
case, nr can be 1 (or 2, etc) when the child finally gets the mutex.
That means your while loop will be skipped (nr<=0 is not true), and
whatever the current value of nr is will be printed on the way out.
I've run this several times, and gotten 1x1, 1x2, and 2x2, multiple
times.
A simple fix for this involves using the cv/mtx pair you've set up for monitoring for changes from main to also monitor startup-start from function. First the code:
The Code
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int nr = -1;
void* function(void* arg)
{
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
// now start waiting (which will unlock the mutex as well, which means
// the main thread will be be able to acquire it and check nr safely
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
printf("Number %d is positive \n",nr);
pthread_mutex_unlock(&mtx);
return NULL;
}
int main()
{
pthread_t tid;
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
// now we know the child is ready to receive signals
int i;
for(i=0;i<3;i++)
{
pthread_mutex_lock(&mtx);
if(i==0)
nr=nr+1;
if(i==1)
nr=nr-2;
if(i==2)
nr=nr+3;
int isPos = (nr>0);
pthread_mutex_unlock(&mtx);
if (isPos)
pthread_cond_signal(&cond);
}
pthread_join(tid,NULL);
return 0;
}
How It Works
The initial value of nr is established as -1. Only the child thread will change this directly to 0, and even then only under the protection of the predicate mutex.
// signal main to start up once we start waiting
pthread_mutex_lock(&mtx);
nr = 0;
pthread_cond_signal(&cond);
Note that after the above three lines, the child still owns the mutex. It atomically releases it and begins waiting for notifications with the first entry into the subsequent loop:
while(nr<=0)
pthread_cond_wait(&cond,&mtx);
Now, back in main, the startup creates the child thread, acquires the mutex, then monitors until nr is zero.
pthread_create(&tid,NULL,function,NULL);
// wait until child is knowingly waiting
pthread_mutex_lock(&mtx);
while (nr != 0)
pthread_cond_wait(&cond, &mtx);
pthread_mutex_unlock(&mtx);
The only way to make it past this is when nr == 0. When that happens, the child must have changed it, but more importantly, it also must be waiting on the condition variable (that is how we got the mutex; remember?) From that point on, the code is similar. Worth noting, I use the pthread initializers to ensure the mutex and cvar are properly stood up. Your original post was missing the cvar initialization.
Lastly, doing multiple-predicate double-duty with a single cvar-mtx pair is easy to mess up, and can be very hard to detect edge cases when you did (mess up, that is). Be careful. This specific example is a hand-off sequence of duties, not concurrent duties, making it fairly trivial, so I'm comfortable in showing it.
Hope it helps.
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.
A Naive question ..
I read before saying - "A MUTEX has to be unlocked only by the thread that locked it."
But I have written a program where THREAD1 locks mutexVar and goes for a sleep. Then THREAD2 can directly unlock mutexVar do some operations and return.
==> I know everyone say why I am doing so ?? But my question is - Is this a right behaviour of MUTEX ??
==> Adding the sample code
void *functionC()
{
pthread_mutex_lock( &mutex1 );
counter++;
sleep(10);
printf("Thread01: Counter value: %d\n",counter);
pthread_mutex_unlock( &mutex1 );
}
void *functionD()
{
pthread_mutex_unlock( &mutex1 );
pthread_mutex_lock( &mutex1 );
counter=10;
printf("Counter value: %d\n",counter);
}
int main()
{
int rc1, rc2;
pthread_t thread1, thread2;
if(pthread_mutex_init(&mutex1, NULL))
printf("Error while using pthread_mutex_init\n");
if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) )
{
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &functionD, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
Pthreads has 3 different kinds of mutexes: Fast mutex, recursive mutex, and error checking mutex. You used a fast mutex which, for performance reasons, will not check for this error. If you use the error checking mutex on Linux you will find you get the results you expect.
Below is a small hack of your program as an example and proof. It locks the mutex in main() and the unlock in the created thread will fail.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
/*** NOTE THE ATTR INITIALIZER HERE! ***/
pthread_mutex_t mutex1 = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
int counter = 0;
void *functionD(void* data)
{
int rc;
if ((rc = pthread_mutex_unlock(&mutex1)) != 0)
{
errno = rc;
perror("other thread unlock result");
exit(1);
}
pthread_mutex_lock(&mutex1);
counter=10;
printf("Thread02: Counter value: %d\n",counter);
return(data);
}
int main(int argc, char *argv[])
{
int rc1;
pthread_t thread1;
if ((rc1 = pthread_mutex_lock(&mutex1)) != 0)
{
errno = rc1;
perror("main lock result");
}
if( (rc1 = pthread_create(&thread1, NULL, &functionD, NULL)))
{
printf("Thread creation failed: %d\n", rc1);
}
pthread_join(thread1, NULL);
}
What you've done is simply not legal, and the behavior is undefined. Mutexes only exclude threads that play by the rules. If you tried to lock mutex1 from thread 2, the thread would be blocked, of course; that's the required thing to do. There's nothing in the spec that says what happens if you try to unlock a mutex you don't own!
A mutex is used to prevent multiple threads from executing code that is only safe for one thread at a time.
To do this a mutex has several features:
A mutex can handle the race conditions associated with multiple threads trying to "lock" the mutex at the same time and always results with one thread winning the race.
Any thread that loses the race gets put to sleep permanently until the mutex is unlocked. The mutex maintains a list of these threads.
A will hand the "lock" to one and only one of the waiting threads when the mutex is unlocked by the thread who was just using it. The mutex will wake that thread.
If that type of pattern is useful for some other purpose then go ahead and use it for a different reason.
Back to your question. Lets say you were protecting some code from multiple thread accesses with a mutex and lets say 5 threads were waiting while thread A was executing the code. If thread B (not one of the ones waiting since they are permanently slept at the moment) unlocks the mutex, another thread will commence executing the code at the same time as thread A. Probably not desired.
Maybe if we knew what you were thinking about using the mutex for we could give a better answer. Are you trying to unlock a mutex after a thread was canceled? Do you have code that can handle 2 threads at a time but not three and there is no mutex that lets 2 threads through at a time?
I am beginner to SO, so please let me know if the question is not clear.
I am using two threads for example A and B. And i have a global variable 'p'.
Thread A is while looping and incrementing the value of 'p'.At the same time B is trying to set the 'p' with some other value(both are two different thread functions).
If I am using mutex for synchronizations, and the thread A get the mutex and incrementation the 'p' in a while loop,but it does not release the mutex.
So my question is that if the thread A doesn’t release the mutex can the thread B access the variable 'p'??
EDIT
The thread B is also protected accses to 'p' using mutex.
If the thread A lock using pthread_mutex_lock(), and doesn’t release it , then what happen if the same thread(A) try to access the lock again(remember the thread A is while looping)
For example
while(1)
{
pthread_mutex_lock(&mutex);
p = 10;
}
Is there any problem with this code if the mutex is never released?
You can still access the variable in thread B as the mutex is a separate object not connected to the variable. If You call mutex lock from thread B before accessing p then the thread B will wait for mutex to be released. In fact the thread A will only execute loop body once as it will wait for the mutex to be released before it can lock it again.
If You don't unlock the mutex then any call to lock the same mutex will wait indefinitely, but the variable will be writable.
In Your example access to variable p is what is called a critical section, or the part of code that is between mutex lock and mutex release.
There is no restriction on mutex, you need to write your program to following the rules of using mutex.
Here is the basic steps to use mutex on shared resource:
Acquire lock first
do job (increase for A, set value for B)
Release lock,
If both A & B follow the rules, then B can't modify it, while A keeps the lock.
Or, if your thread B don't acquire the lock first, it of cause could modify the variable, but that would be a bug for concurrent programming.
And, by the way, you can also use condition together with mutex, so that you can let threads wait & notify each other, instead of looping all the time which is a waste of machine resource.
For your updated question
On linux, in c, there are mainly 3 methods to acquire lock of mutex, what happens when a thread can't get the lock depends on which methods u use.
int pthread_mutex_lock(pthread_mutex_t * mutex );
if it's already locked by another thread, then it block until the lock is unlocked,
int pthread_mutex_trylock(pthread_mutex_t * mutex );
similar to pthread_mutex_lock(), but it won't block, instead return error EBUSY,
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
similar to pthread_mutex_lock(), but it will wait for a timeout before return error ETIMEDOUT,
Simple example of statically initialized mutex
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
static int p = 0;
static pthread_mutex_t locker = PTHREAD_MUTEX_INITIALIZER;
static void *
threadFunc(void *arg)
{
int err;
err = pthread_mutex_lock(&locker);
if (err != 0){
perror("pthread_mutex_lock failed");
exit(1);
}
p++;
err = pthread_mutex_unlock(&locker);
if (err != 0){
perror("pthread_mutex_unlock failed");
exit(1);
}
return NULL;
}
int
main(int argc, char *argv[])
{
pthread_t A, B;
pthread_create(&A, NULL, threadFunc, NULL);
pthread_create(&B, NULL, threadFunc, NULL);
pthread_join(A, NULL);
pthread_join(B, NULL);
printf("p = %d\n", p);
return 0;
}
Error checking in main is omitted for brevity but should be used. If you do not release mutex program will never finish, thread B will never get lock.
I am trying to write a code that does not block main() when pthread_join() is called:
i.e. basically trying to implement my previous question mentioned below:
https://stackoverflow.com/questions/24509500/pthread-join-and-main-blocking-multithreading
And the corresponding explanation at:
pthreads - Join on group of threads, wait for one to exit
As per suggested answer:
You'd need to create your own version of it - e.g. an array of flags (one flag per thread) protected by a mutex and a condition variable; where just before "pthread_exit()" each thread acquires the mutex, sets its flag, then does "pthread_cond_signal()". The main thread waits for the signal, then checks the array of flags to determine which thread/s to join (there may be more than one thread to join by then).
I have tried as below:
My status array which keeps a track of which threads have finished:
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
The thread routine, it sets the corresponding array element when the thread finishes and also signals the condition variable:
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
I am not able to write the corresponding parts pthread_join() and pthread_cond_wait() functions. There are a few things which I am not able to implement.
1) How to write corresponding part pthread_cond_wait() in my main()?
2) I am trying to write it as:
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
But it does not enter the while loop.
3) How to use pthread_join() so that I can get the return value stored in my arg[i].returnStatus
i.e. where to put below statement in my main:
`pthread_join(T[i],&(arg[i].returnStatus));`
COMPLETE CODE
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#define THREAD_NUM 5
#define FALSE 0
#define TRUE 1
void waitFor (unsigned int secs) {
time_t retTime;
retTime = time(0) + secs; // Get finishing time.
while (time(0) < retTime); // Loop until it arrives.
}
typedef struct {
int Finish_Status[THREAD_NUM];
int signalled;
pthread_mutex_t mutex;
pthread_cond_t FINISHED;
}THREAD_FINISH_STATE;
typedef struct {
int id;
void* returnStatus;
}THREAD_ARGUMENT;
THREAD_FINISH_STATE ThreadFinishStatus;
void initializeState(THREAD_FINISH_STATE* state)
{
int i=0;
state->signalled=FALSE;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_init(&(state->mutex),NULL);
pthread_cond_init(&(state->FINISHED),NULL);
}
void destroyState(THREAD_FINISH_STATE* state)
{
int i=0;
for(i=0;i<THREAD_NUM;i++)
{
state->Finish_Status[i]=FALSE;
}
pthread_mutex_destroy(&(state->mutex));
pthread_cond_destroy(&(state->FINISHED));
}
void* THREAD_ROUTINE(void* arg)
{
THREAD_ARGUMENT* temp=(THREAD_ARGUMENT*) arg;
printf("Thread created with id %d\n",temp->id);
waitFor(5);
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
ThreadFinishStatus.Finish_Status[temp->id]=TRUE;
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
{
pthread_cond_signal(&(ThreadFinishStatus.FINISHED));
printf("Signal that thread %d finished\n",temp->id);
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
pthread_exit((void*)(temp->id));
}
int main()
{
THREAD_ARGUMENT arg[THREAD_NUM];
pthread_t T[THREAD_NUM];
int i=0;
initializeState(&ThreadFinishStatus);
for(i=0;i<THREAD_NUM;i++)
{
arg[i].id=i;
}
for(i=0;i<THREAD_NUM;i++)
{
pthread_create(&T[i],NULL,THREAD_ROUTINE,(void*)&arg[i]);
}
/*
Join only if signal received
*/
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
//Wait
while((ThreadFinishStatus.signalled != TRUE){
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled==FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
destroyState(&ThreadFinishStatus);
return 0;
}
Here is an example of a program that uses a counting semaphore to watch as threads finish, find out which thread it was, and review some result data from that thread. This program is efficient with locks - waiters are not spuriously woken up (notice how the threads only post to the semaphore after they've released the mutex protecting shared state).
This design allows the main program to process the result from some thread's computation immediately after the thread completes, and does not require the main wait for all threads to complete. This would be especially helpful if the running time of each thread varied by a significant amount.
Most importantly, this program does not deadlock nor race.
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <queue>
void* ThreadEntry(void* args );
typedef struct {
int threadId;
pthread_t thread;
int threadResult;
} ThreadState;
sem_t completionSema;
pthread_mutex_t resultMutex;
std::queue<int> threadCompletions;
ThreadState* threadInfos;
int main() {
int numThreads = 10;
int* threadResults;
void* threadResult;
int doneThreadId;
sem_init( &completionSema, 0, 0 );
pthread_mutex_init( &resultMutex, 0 );
threadInfos = new ThreadState[numThreads];
for ( int i = 0; i < numThreads; i++ ) {
threadInfos[i].threadId = i;
pthread_create( &threadInfos[i].thread, NULL, &ThreadEntry, &threadInfos[i].threadId );
}
for ( int i = 0; i < numThreads; i++ ) {
// Wait for any one thread to complete; ie, wait for someone
// to queue to the threadCompletions queue.
sem_wait( &completionSema );
// Find out what was queued; queue is accessed from multiple threads,
// so protect with a vanilla mutex.
pthread_mutex_lock(&resultMutex);
doneThreadId = threadCompletions.front();
threadCompletions.pop();
pthread_mutex_unlock(&resultMutex);
// Announce which thread ID we saw finish
printf(
"Main saw TID %d finish\n\tThe thread's result was %d\n",
doneThreadId,
threadInfos[doneThreadId].threadResult
);
// pthread_join to clean up the thread.
pthread_join( threadInfos[doneThreadId].thread, &threadResult );
}
delete threadInfos;
pthread_mutex_destroy( &resultMutex );
sem_destroy( &completionSema );
}
void* ThreadEntry(void* args ) {
int threadId = *((int*)args);
printf("hello from thread %d\n", threadId );
// This can safely be accessed since each thread has its own space
// and array derefs are thread safe.
threadInfos[threadId].threadResult = rand() % 1000;
pthread_mutex_lock( &resultMutex );
threadCompletions.push( threadId );
pthread_mutex_unlock( &resultMutex );
sem_post( &completionSema );
return 0;
}
Pthread conditions don't have "memory"; pthread_cond_wait doesn't return if pthread_cond_signal is called before pthread_cond_wait, which is why it's important to check the predicate before calling pthread_cond_wait, and not call it if it's true. But that means the action, in this case "check which thread to join" should only depend on the predicate, not on whether pthread_cond_wait is called.
Also, you might want to make the while loop actually wait for all the threads to terminate, which you aren't doing now.
(Also, I think the other answer about "signalled==FALSE" being harmless is wrong, it's not harmless, because there's a pthread_cond_wait, and when that returns, signalled would have changed to true.)
So if I wanted to write a program that waited for all threads to terminate this way, it would look more like
pthread_mutex_lock(&(ThreadFinishStatus.mutex));
// AllThreadsFinished would check that all of Finish_Status[] is true
// or something, or simpler, count the number of joins completed
while (!AllThreadsFinished()) {
// Wait, keeping in mind that the condition might already have been
// signalled, in which case it's too late to call pthread_cond_wait,
// but also keeping in mind that pthread_cond_wait can return spuriously,
// thus using a while loop
while (!ThreadFinishStatus.signalled) {
pthread_cond_wait(&(ThreadFinishStatus.FINISHED), &(ThreadFinishStatus.mutex));
}
printf("Main Thread signalled\n");
ThreadFinishStatus.signalled=FALSE; //Reset signalled
//check which thread to join
}
pthread_mutex_unlock(&(ThreadFinishStatus.mutex));
Your code is racy.
Suppose you start a thread and it finishes before you grab the mutex in main(). Your while loop will never run because signalled was already set to TRUE by the exiting thread.
I will echo #antiduh's suggestion to use a semaphore that counts the number of dead-but-not-joined threads. You then loop up to the number of threads spawned waiting on the semaphore. I'd point out that the POSIX sem_t is not like a pthread_mutex in that sem_wait can return EINTR.
Your code appears fine. You have one minor buglet:
ThreadFinishStatus.signalled==FALSE; //Reset signalled
This does nothing. It tests whether signalled is FALSE and throws away the result. That's harmless though since there's nothing you need to do. (You never want to set signalled to FALSE because that loses the fact that it was signalled. There is never any reason to unsignal it -- if a thread finished, then it's finished forever.)
Not entering the while loop means signalled is TRUE. That means the thread already set it, in which case there is no need to enter the loop because there's nothing to wait for. So that's fine.
Also:
ThreadFinishStatus.signalled=TRUE;
if(ThreadFinishStatus.signalled==TRUE)
There's no need to test the thing you just set. It's not like the set can fail.
FWIW, I would suggest re-architecting. If the existing functions like pthread_join don't do exactly what you want, just don't use them. If you're going to have structures that track what work is done, then totally separate that from thread termination. Since you will already know what work is done, what different does it make when and how threads terminate? Don't think of this as "I need a special way to know when a thread terminates" and instead think of this "I need to know what work is done so I can do other things".