I am trying to work with a scenario where a producer produces a value into the buffer (state.value) and multiple consumers are reading the buffer and updating it in the array. Below is the code.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
pthread_cond_t prod, cons;
static int count = 0;
struct shared_state{
int done;
int value;
int value_available;
int *array;
int j;
}state;
void * producer(void *arg){
int a[] = {12,11,10,9,8,7};
int size = sizeof(a)/sizeof(a[0]);
int i = 0;
while(i<size){
pthread_mutex_lock(&mutex);
while(state.value_available)
pthread_cond_wait(&prod, &mutex);
state.value = a[i++];
printf("In producer: %d\n",state.value);
state.value_available = 1;
pthread_cond_signal(&cons);
pthread_mutex_unlock(&mutex);
}
state.done = 1;
count++;
printf("Producer count: %d\n",count);
pthread_exit(NULL);
}
void * consumer(void *arg){
while(!(state.done)){
pthread_mutex_lock(&mutex);
while(!state.value_available)
pthread_cond_wait(&cons,&mutex);
state.array[(state.j)] = state.value;
printf("In consumer: %d\t%d\n",state.array[state.j], state.j);
(state.j)++;
state.value_available = 0;
pthread_cond_signal(&prod);
pthread_mutex_unlock(&mutex);
}
int i;
for(i=0;i<6;i++)
printf("%d-->",state.array[i]);
printf("\n");
count++;
printf("Consumer count: %d\n",count);
}
int main(void){
state.done = 0;
pthread_t pro,con,con2;
state.value_available = 0;
state.j = 0;
state.array = (int *)malloc(sizeof(int)*6);
pthread_create(&pro, NULL, producer, (void *)NULL);
pthread_create(&con, NULL, consumer, (void *)NULL);
pthread_create(&con2, NULL, consumer, (void *)NULL);
pthread_join(pro,NULL);
pthread_join(con,NULL);
pthread_join(con2,NULL);
pthread_exit(NULL);
printf("\n");
return 0;
}
Below is the output I am receiving. However, the second consumer thread doesn't exit and runs into an infinite loop. It'll be helpful if someone could help me in identifying the error. Thanks.
In producer: 12
In consumer: 12
In producer: 11
In consumer: 11
In producer: 10
In consumer: 10
In producer: 9
In consumer: 9
In producer: 8
In consumer: 8
In producer: 7
Producer count: 1
In consumer: 7
Consumer array: 12-->11-->10-->9-->8-->7-->
Consumer count: 2
In the first place, you fail to initialize your mutex and your condition variables. Because they are globals, their initial state is not for that reason indeterminate, but neither is it necessarily valid. You must either use the appropriate initialization functions or initialize with the for-purpose initialization macros. For example,
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t prod = PTHREAD_COND_INITIALIZER;
pthread_cond_t cons = PTHREAD_COND_INITIALIZER;
You appear to be lucking out on that issue, but that does not mean you shouldn't fix it.
In the second place, you do not check the return values of your function calls for error codes. You really must do that for your code to be robust. Errors happen both because of broken code and because of uncontrolled runtime issues, and if you assume that your function calls will always succeed then you will come to grief sooner or later.
You have a bigger problem, however: pthread_cond_signal() wakes one thread waiting on the given condition variable, if indeed any are waiting. It is likely that both consumer threads will be blocked on the condition when the producer signals the CV for the last time. In that case, one wakes and performs its processing, but the other remains blocked. Because the consumers perform a proper check on the condition predicate after waking from their wait, you can solve that problem by using pthread_cond_broadcast() instead.
But that's only half a solution. Because you indeed do perform a proper predicate check, and because the consumer will update the shared state so that its own predicate is false before it releases the mutex, the second consumer would just resume waiting anyway if it did wake from the wait. Besides, what would it do if it did not resume waiting? There is no value available for it to consume, and no alternative path for it to take.
Bottom line:
Your producer must broadcast to the consumers' CV instead of signaling to it, at least after producing its last item.
When the consumer wakes from waiting on the CV, it must check not only whether a value is available, but also whether the producer is done. It must not resume waiting under either circumstance, but it must consume a value only if one is actually available.
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.
I am trying to learn how to use conditional variables properly in C.
As an exercise for myself I am trying to make a small program with 2 threads that print "Ping" followed by "Pong" in an endless loop.
I have written a small program:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
sleep(0.5);
printf("ping\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
pthread_cond_wait(&cond,&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_cond_wait(&cond,&lock);
pthread_mutex_lock(&lock);
sleep(0.5);
printf("pong\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
while(1){
sleep(1);
i++;
}
return EXIT_SUCCESS;
}
And when running this program the output I get is:
main
thread 1 started
thread 2 started
ping
Any idea what is the reason the program does not execute as expected?
Thanks in advance.
sleep takes an integer, not a floating point. Not sure what sleep(0) does on your system, but it might be one of your problems.
You need to hold the mutex while calling pthread_cond_wait.
Naked condition variables (that is condition variables that don't indicate that there is a condition to read somewhere else) are almost always wrong. A condition variable indicates that something we are waiting for might be ready to be consumed, they are not for signalling (not because it's illegal, but because it's pretty hard to get them right for pure signalling). So in general a condition will look like this:
/* consumer here */
pthread_mutex_lock(&something_mutex);
while (something == 0) {
pthread_cond_wait(&something_cond, &something_mutex);
}
consume(something);
pthread_mutex_unlock(&something_mutex);
/* ... */
/* producer here. */
pthread_mutex_lock(&something_mutex);
something = 4711;
pthread_cond_signal(&something_cond, &something_mutex);
pthread_mutex_unlock(&something_mutex);
It's a bad idea to sleep while holding locks.
T1 and T2 are not valid functions to use as functions to pthread_create they are supposed to take arguments. Do it right.
You are racing yourself in each thread between cond_signal and cond_wait, so it's not implausible that each thread might just signal itself all the time. (correctly holding the mutex in the calls to pthread_cond_wait may help here, or it may not, that's why I said that getting naked condition variables right is hard, because it is).
First of all you should never use sleep() to synchronize threads (use nanosleep() if you need to reduce output speed). You may need (it's a common use) a shared variable ready to let each thread know that he can print the message. Before you make a pthread_cond_wait() you must acquire the lock because the pthread_cond_wait() function shall block on a condition variable. It shall be called with mutex locked by the calling thread or undefined behavior results.
Steps are:
Acquire the lock
Use wait in a while with a shared variable in guard[*]
Do stuffs
Change the value of shared variable for synchronize (if you've one) and signal/broadcast that you finished to work
Release the lock
Steps 4 and 5 can be reversed.
[*]You use pthread_cond_wait() to release the mutex and block the thread on the condition variable and when using condition variables there is always a Boolean predicate involving shared variables associated with each condition wait that is true if the thread should proceed because spurious wakeups may occur. watch more here
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int ready = 0;
void* T1(){
printf("thread 1 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 1){
pthread_cond_wait(&cond,&lock);
}
printf("ping\n");
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void* T2(){
printf("thread 2 started\n");
while(1)
{
pthread_mutex_lock(&lock);
while(ready == 0){
pthread_cond_wait(&cond,&lock);
}
printf("pong\n");
ready = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
int main(void)
{
int i = 1;
pthread_t t1;
pthread_t t2;
printf("main\n");
pthread_create(&t1,NULL,&T1,NULL);
pthread_create(&t2,NULL,&T2,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return EXIT_SUCCESS;
}
You should also use pthread_join() in main instead of a while(1)
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
In the code below:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mtx;
pthread_cond_t cond;
int how_many = 10;
int pool = 0;
void * producer(void * ptr)
{
while (how_many > 0)
{
pthread_mutex_lock(&mtx);
printf("producer: %d\n", how_many);
pool = how_many;
how_many--;
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
void * consumer(void * ptr)
{
while (how_many > 0)
{
pthread_mutex_lock(&mtx);
pthread_cond_wait(&cond, &mtx);
printf("consumer: %d\n", pool);
pool = 0;
pthread_mutex_unlock(&mtx);
}
pthread_exit(0);
}
int main(int argc, char ** argv)
{
pthread_t prod, cons;
pthread_mutex_init(&mtx, 0);
pthread_cond_init(&cond, 0);
pthread_create(&cons, 0, consumer, 0);
pthread_create(&prod, 0, producer, 0);
pthread_join(prod, 0);
pthread_join(cons, 0);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mtx);
return 0;
}
I'm not getting the expected output.
Expected output:
Producer:10
Consumer:10
Producer:9
Consumer:9
Producer:8
Consumer:8
Producer:7
Consumer:7
Producer:6
Consumer:6
Producer:5
Consumer:5
Producer:4
Consumer:4
Producer:3
Consumer:3
Producer:2
Consumer:2
Producer:1
Consumer:1
Actual output:
producer: 10
producer: 9
producer: 8
producer: 7
producer: 6
producer: 5
producer: 4
producer: 3
producer: 2
producer: 1
Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?
Will it be dead lock?
My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. Is that true?
Mutexes provide only mutual exclusion (when used properly); they do not themselves provide a mechanism for blocking on a specific event to happen or until a specific condition is satisfied. That's what condition variables are for (and semaphores, if you want to go a little lower-level).
Your code provides for the consumer to wait on the producer to produce, but not for the producer to wait on the consumer to consume before it continues. If you want the two threads to alternate, then you need a second condition variable to provide for the latter.
Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?
will it be dead lock?
My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. is that true?
Rather than asking your friends -- or the Internet -- have you considered reading the documentation? Here's the way the man page describes it:
These functions atomically release mutex [...]. Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.
That is, the thread calling pthread_cond_wait() does not hold the mutex locked while it is waiting, but it reacquires the mutex before it returns (which may involve an indeterminate delay between the thread receiving the signal and the function call returning).
Additionally, always remember that a thread can wake up spurriously from waiting on a condition variable. It is essential to check upon wakeup whether the condition is in fact satisfied, and to resume waiting if not.
Here's a way you could structure the producer:
void * producer(void * ptr)
{
pthread_mutex_lock(&mtx);
while (how_many > 0)
{
if (pool == 0) {
printf("producer: %d\n", how_many);
pool = how_many;
how_many--;
pthread_cond_signal(&full_cond);
}
pthread_cond_wait(&empty_cond, &mtx);
}
pthread_mutex_unlock(&mtx);
pthread_exit(0);
}
Note that:
I have renamed your original condition variable and introduced a new one. There is now full_cond, indicating that the pool (of capacity 1) is full, and empty_cond, indicating that the pool is empty.
The whole loop is protected by a mutex. This is fine because it performs a pthread_cond_wait() naming that mutex; the other threads will be able to run while the the producer is waiting. The mutex ensures that access to the how_many and pool variables is correctly synchronized.
The loop protects against spurrious wakeup by testing pool to verify that it really is empty. If not, it loops back to the wait without doing anything else.
For this to work correctly, the consumer requires corresponding changes (left as an exercise for you).
You are checking how_many out of the locked section. You need to restructure you code so that reading the variable is covered by a lock or so that it is C11 _Atomic.
Even then, your code's output is likely not going to be the way you want it as the scheduling of the threads is pretty much unpredictable.
For your expected output you can use the locking mechanism like below,
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
sem_t mutex1;
sem_t mutex2;
int main()
{
pthread_t thread1, thread2;
sem_init(&mutex1, 0, 1);
sem_init(&mutex2, 0, 0);
pthread_create( &thread1, NULL, &producer, NULL)
pthread_create( &thread2, NULL, &consumer, NULL)
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
return 0;
}
void producer()
{
sem_wait(&mutex1);
:
:
sem_post(&mutex2);
}
void consumer ()
{
sem_wait(&mutex2);
:
:
sem_post(&mutex1);
}
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".