The version of pthread_join() that does not block main(): POSIX - c

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".

Related

Global variable not changing in thread?

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.

Conditional Variables with multithreading

I am working on the dining philosophers problem, where n philosophers take turns thinking and eating. I would like to have a version of this where the philosophers will eat in the order of their id: 0,1,2,3,4...,but my threads keep getting blocked. My threads start by calling PhilosopherThread().
void putDownChopsticks(int threadIndex){
//finished eating
pindex++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void pickUpChopsticks(int threadIndex){
pthread_mutex_lock(&lock);
while(pindex != threadIndex){
pthread_cond_wait(&cond, &lock);
}
//lets go eat
}
void eating(){
//put thread to sleep
}
void thinking(){
//put thread to sleep
}
void* PhilosopherThread(void *x){
int *index = x;
thinking(); //just puts thread to sleep to simulate thinking
pickUpChopsticks(*index);
eating(); //just puts thread to sleep to simulate eating
putDownChopsticks(*index);
return NULL;
}
I'm having a bit of trouble trying to get the philosophers in order. I can only get the first 2 threads to eat before the threads get blocked.
Edit: as far as i know im doing this right. I first lock the mutex, then I check if pindex is the current thread id, if its not the thread will wait until pindex does equal the id. Then the thread can go eat and once where done, we incread pindex, signal that the thread is done, and unlock the mutex.
This code sometimes works and sometimes does not. First, since you did not provide a complete program, here are the missing bits I used for testing purposes:
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t cond;
static pthread_mutex_t lock;
static pindex;
/* ... your code ... */
int main () {
int id[5], i;
pthread_t tid[5];
for (i = 0; i < 5; ++i) {
id[i] = i;
pthread_create(tid+i, 0, PhilosopherThread, id+i);
}
for (i = 0; i < 5; ++i) pthread_join(tid[i], 0);
exit(0);
}
The critical piece to notice is how you wake up the next philosopher:
pthread_cond_signal(&cond);
This call will only wake up one thread. But, which thread is at the discretion of the OS. Therefore, if it does not happen to wake up the philosopher that is supposed to wake up, no other philosopher is woken up.
A simple fix would be to wake up all waiting threads instead of just one. The philosophers that don't match will go back to waiting, and the one that is supposed to go next will go.
pthread_cond_broadcast(&cond);
However, since each thread knows which philosopher should wake up, you could change your solution to allow that to happen. One way could be to implement a separate condition variable per philosopher, and use pthread_cond_signal() on the next philosopher's condition variable.

pthread not working using pthread_cond_signal() and pthread_cond_wait()

I using pthread_cond_wait() and pthread_cond_signal() function to create a multithreaded program. It working correctly if condition correct, but condition incorrect, it not working, it not ignore function printinput(), it stay here, not run continue. Can you help me checking this error?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
//Read input value
void* readinput(void *arg)
{
pthread_mutex_lock(&mutex);
int a;
printf("Input:");
scanf("%d",&a);
printf("Value: %d\n",a);
/*
if condition correct then "printinput" function
else ignore that function
*/
if (a>=2 && a<=8)
{
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
pthread_exit((void *)a);
}
//print input value if condition correctly
void* printinput(void *arg)
{
pthread_mutex_lock(&mutex);
//Block and wait for cond Singal
pthread_cond_wait(&cond,&mutex);
printf("Your value between 2 and 8 \n\n");
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_t th1;
pthread_t th2;
while (1)
{
//Create pthread
pthread_create(&th1,NULL,&printinput,NULL);
pthread_create(&th2,NULL,&readinput,NULL);
//Wait pthread done
pthread_join(th1,NULL);
pthread_join(th2,NULL);
Sleep(1000);
}
}
Result:
Input:5
Value: 5
Your value between 2 and 8
Input:10 Value: 10
pthread_cond_wait() suspends the current thread until the relevant condition is signalled.
For input 5 the first thread signals the condition as it's part of if (a >= 2 && a <= 8) block.
For input 10 the above block is skipped so the condition is never signalled. Therefore the second thread is never woken up and is stuck forever.
Additionally, note there is race condition and I'm actually surprised that the program is often working. In case the first thread locks the mutex, the second thread doesn't enter the mutex section until the first thread function is finished, therefore the condition is signalled before the wait on that condition is invoked. In such situation the second thread would be stuck forever as well.
For the solution working in the way you expect (i.e. consuming true/false from the first thread in the second thread), I'd suggest implementing a queue into which the first thread sends the outputs and the second thread consumes it. It'll fix the race condition too. For the implementation see for example https://stackoverflow.com/a/4577987/4787126

Output in multi threading program

Writing my basic programs on multi threading and I m coming across several difficulties.
In the program below if I give sleep at position 1 then value of shared data being printed is always 10 while keeping sleep at position 2 the value of shared data is always 0.
Why this kind of output is coming ?
How to decide at which place we should give sleep.
Does this mean that if we are placing a sleep inside the mutex then the other thread is not being executed at all thus the shared data being 0.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
pthread_mutex_t lock;
int shared_data = 0;
void * function(void *arg)
{
int i ;
for(i =0; i < 10; i++)
{
pthread_mutex_lock(&lock);
shared_data++;
pthread_mutex_unlock(&lock);
}
pthread_exit(NULL);
}
int main()
{
pthread_t thread;
void * exit_status;
int i;
pthread_mutex_init(&lock, NULL);
i = pthread_create(&thread, NULL, function, NULL);
for(i =0; i < 10; i++)
{
sleep(1); //POSITION 1
pthread_mutex_lock(&lock);
//sleep(1); //POSITION 2
printf("Shared data value is %d\n", shared_data);
pthread_mutex_unlock(&lock);
}
pthread_join(thread, &exit_status);
pthread_mutex_destroy(&lock);
}
When you sleep before you lock the mutex, then you're giving the other thread plenty of time to change the value of the shared variable. That's why you're seeing a value of "10" with the 'sleep' in position #1.
When you grab the mutex first, you're able to lock it fast enough that you can print out the value before the other thread has a chance to modify it. The other thread sits and blocks on the pthread_mutex_lock() call until your main thread has finished sleeping and unlocked it. At that point, the second thread finally gets to run and alter the value. That's why you're seeing a value of "0" with the 'sleep' at position #2.
This is a classic case of a race condition. On a different machine, the same code might not display "0" with the sleep call at position #2. It's entirely possible that the second thread has the opportunity to alter the value of the variable once or twice before your main thread locks the mutex. A mutex can ensure that two threads don't access the same variable at the same time, but it doesn't have any control over the order in which the two threads access it.
I had a full explanation here but ended up deleting it. This is a basic synchronization problem and you should be able to trace and identify it before tackling anything more complicated.
But I'll give you a hint: It's only the sleep() in position 1 that matters; the other one inside the lock is irrelevant as long as it doesn't change the code outside the lock.

How can I wait for any/all pthreads to complete?

I just want my main thread to wait for any and all my (p)threads to complete before exiting.
The threads come and go a lot for different reasons, and I really don't want to keep track of all of them - I just want to know when they're all gone.
wait() does this for child processes, returning ECHILD when there are no children left, however wait does not (appear to work with) (p)threads.
I really don't want to go through the trouble of keeping a list of every single outstanding thread (as they come and go), then having to call pthread_join on each.
As there a quick-and-dirty way to do this?
Do you want your main thread to do anything in particular after all the threads have completed?
If not, you can have your main thread simply call pthread_exit() instead of returning (or calling exit()).
If main() returns it implicitly calls (or behaves as if it called) exit(), which will terminate the process. However, if main() calls pthread_exit() instead of returning, that implicit call to exit() doesn't occur and the process won't immediately end - it'll end when all threads have terminated.
http://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_exit.html
Can't get too much quick-n-dirtier.
Here's a small example program that will let you see the difference. Pass -DUSE_PTHREAD_EXIT to the compiler to see the process wait for all threads to finish. Compile without that macro defined to see the process stop threads in their tracks.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
static
void sleep(int ms)
{
struct timespec waittime;
waittime.tv_sec = (ms / 1000);
ms = ms % 1000;
waittime.tv_nsec = ms * 1000 * 1000;
nanosleep( &waittime, NULL);
}
void* threadfunc( void* c)
{
int id = (int) c;
int i = 0;
for (i = 0 ; i < 12; ++i) {
printf( "thread %d, iteration %d\n", id, i);
sleep(10);
}
return 0;
}
int main()
{
int i = 4;
for (; i; --i) {
pthread_t* tcb = malloc( sizeof(*tcb));
pthread_create( tcb, NULL, threadfunc, (void*) i);
}
sleep(40);
#ifdef USE_PTHREAD_EXIT
pthread_exit(0);
#endif
return 0;
}
The proper way is to keep track of all of your pthread_id's, but you asked for a quick and dirty way so here it is. Basically:
just keep a total count of running threads,
increment it in the main loop before calling pthread_create,
decrement the thread count as each thread finishes.
Then sleep at the end of the main process until the count returns to 0.
.
volatile int running_threads = 0;
pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
void * threadStart()
{
// do the thread work
pthread_mutex_lock(&running_mutex);
running_threads--;
pthread_mutex_unlock(&running_mutex);
}
int main()
{
for (i = 0; i < num_threads;i++)
{
pthread_mutex_lock(&running_mutex);
running_threads++;
pthread_mutex_unlock(&running_mutex);
// launch thread
}
while (running_threads > 0)
{
sleep(1);
}
}
If you don't want to keep track of your threads then you can detach the threads so you don't have to care about them, but in order to tell when they are finished you will have to go a bit further.
One trick would be to keep a list (linked list, array, whatever) of the threads' statuses. When a thread starts it sets its status in the array to something like THREAD_STATUS_RUNNING and just before it ends it updates its status to something like THREAD_STATUS_STOPPED. Then when you want to check if all threads have stopped you can just iterate over this array and check all the statuses.
Don't forget though that if you do something like this, you will need to control access to the array so that only one thread can access (read and write) it at a time, so you'll need to use a mutex on it.
you could keep a list all your thread ids and then do pthread_join on each one,
of course you will need a mutex to control access to the thread id list. you will
also need some kind of list that can be modified while being iterated on, maybe a std::set<pthread_t>?
int main() {
pthread_mutex_lock(&mutex);
void *data;
for(threadId in threadIdList) {
pthread_mutex_unlock(&mutex);
pthread_join(threadId, &data);
pthread_mutex_lock(&mutex);
}
printf("All threads completed.\n");
}
// called by any thread to create another
void CreateThread()
{
pthread_t id;
pthread_mutex_lock(&mutex);
pthread_create(&id, NULL, ThreadInit, &id); // pass the id so the thread can use it with to remove itself
threadIdList.add(id);
pthread_mutex_unlock(&mutex);
}
// called by each thread before it dies
void RemoveThread(pthread_t& id)
{
pthread_mutex_lock(&mutex);
threadIdList.remove(id);
pthread_mutex_unlock(&mutex);
}
Thanks all for the great answers! There has been a lot of talk about using memory barriers etc - so I figured I'd post an answer that properly showed them used for this.
#define NUM_THREADS 5
unsigned int thread_count;
void *threadfunc(void *arg) {
printf("Thread %p running\n",arg);
sleep(3);
printf("Thread %p exiting\n",arg);
__sync_fetch_and_sub(&thread_count,1);
return 0L;
}
int main() {
int i;
pthread_t thread[NUM_THREADS];
thread_count=NUM_THREADS;
for (i=0;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Note that the __sync macros are "non-standard" GCC internal macros. LLVM supports these too - but if your using another compiler, you may have to do something different.
Another big thing to note is: Why would you burn an entire core, or waste "half" of a CPU spinning in a tight poll-loop just waiting for others to finish - when you could easily put it to work? The following mod uses the initial thread to run one of the workers, then wait for the others to complete:
thread_count=NUM_THREADS;
for (i=1;i<NUM_THREADS;i++) {
pthread_create(&thread[i],0L,threadfunc,&thread[i]);
}
threadfunc(&thread[0]);
do {
__sync_synchronize();
} while (thread_count);
printf("All threads done\n");
}
Note that we start creating the threads starting at "1" instead of "0", then directly run "thread 0" inline, waiting for all threads to complete after it's done. We pass &thread[0] to it for consistency (even though it's meaningless here), though in reality you'd probably pass your own variables/context.

Resources