About threads and condition variable and synchronise - c

i am trying to understand the condition variables in thread programming can anyone explain how it works with the mutex and what are the condition variable so it can synchronise threads??
condition variables and threads

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

Related

Pthread execute unexpectedly in C

I want to let pthreads can run their task in a specified order:
thread 1 -> thread 3 -> thread 2
When I run my code, I found the result is not fixed.
My OS is Ubuntu 16.04
Sometimes the result is (unexpectd) :
Before creating the threads
In thread1
In thread2
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
In thread3
Sometimes the result is (expectd) :
Before creating the threads
In thread1
In thread2
In thread3
!!!!!!!!!!!!!!!!!!
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
I am thread2 generating the final report and inserting into a table
I am thread1 generating the final report and inserting into a table
I am thread3 generating the final report and inserting into a table
below is my code:
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <signal.h>
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond1, &lock1);
printf("I am thread1 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond2, &lock2);
printf("I am thread2 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
//Add your business logic(parallel execution codes) here
pthread_cond_wait(&cond3, &lock3);
printf("I am thread3 generating the final report and inserting into a table \n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
void my_alarm_handler(int a)
{
TRUE = 0;//重新設定
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
signal( SIGALRM, my_alarm_handler );
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
alarm(1);
//TRUE = 0;/* Stop all the thread */
/* this is how we join thread before exit from a system */
printf("!!!!!!!!!!!!!!!!!!\n");
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
return 0;
}
What wrong make the result is not fixed?
thank you in advance!
You are using your condition variables incorrectly. As the Linux manual page for pthread_cond_wait() puts it:
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. Spurious wakeups from the
pthread_cond_timedwait() or pthread_cond_wait() functions may occur.
Since the return from pthread_cond_timedwait() or pthread_cond_wait()
does not imply anything about the value of this predicate, the
predicate should be re-evaluated upon such return.
That means that it is not appropriate for a thread to interpret returning from a pthread_cond_wait() as an indication that it should proceed. Instead, it should interpret such a return as a sign that it should check some condition involving one or more shared variables to determine whether it should proceed. If the condition is not satisfied then typically, it should wait some more. It usually is appropriate to check the condition before waiting the first time, too, to avoid missing a signal.
Of course, all accesses to a shared variable should be performed under protection of the same mutex, at least if any of them may be writes.
On the receiving side, that all looks something like this:
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
_Bool should_proceed1 = 0;
void *thread1(void *arg) {
pthread_mutex_lock(&lock1);
while (!should_proceed1) {
pthread_cond_wait(&cond1, &lock1);
}
pthread_mutex_unlock(&lock1);
// ...
}
On the signaling side, it might look like this:
pthread_mutex_lock(&lock1);
should_proceed1 = 1;
pthread_mutex_unlock(&lock1);
pthread_cond_signal(&cond1);
Note that the shared variable should_proceed1 is accessed under protection of the same mutex in both places, and that this is also the mutex that the waiting thread associates with the CV for its wait. Also, the pthread_cond_signal() call can happen inside the mutex-protected region, too -- you don't have to unlock the mutex first -- but although a waiting thread will wake immediately (if there are any), it will not proceed until it can reacquire the mutex.
Use of pthread_cond_wait outside of a condition (usually a loop) testing some condition dependent on the state protected by the mutex is always an error. In the comments, dragosht noted:
You're not waiting for thread1 to wait on the condition variable
But there's no way to "wait on a thread to wait on the condition variable". Instead, the thread must not wait on the condition variable if the condition it's waiting for has already been satisfied.
Instead you should be doing something like:
while (next_to_run != MY_NUMBER)
pthread_cond_wait(&cond, &lock);
and the signaling thread should be setting next_to_run before signaling (with the mutex held).

Which thread would be notified by pthread_cond_signal?

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

mutex locking-unlocking producer-consumer scenario [duplicate]

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?

Using pthread_cond_t to signal end of execution

I am using pthread_cond_t to signal the end of execution of child threads to the main thread. Since I'm not synchronizing the access to a shared resource, I wonder what the loop embracing pthread_cond_wait would be? Here's what I have:
pthread_mutex_t mutex;
pthread_cond_t cond;
int main(int argc, char *argv[])
{
pthread_cond_init(&cond, NULL);
cond = PTHREAD_COND_INITIALIZER;
pthread_create(&tid1, NULL, func1, NULL);
pthread_create(&tid2, NULL, func2, NULL);
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
//Join the thread that first completes
}
void *func1(void *arg)
{
....
pthread_cond_signal(&cond);
pthread_exit((void *) 1);
}
void *func2(void *arg)
{
....
pthread_cond_signal(&cond);
pthread_exit((void *) 1);
}
Would the main thread, by default, wait until thread1 or thread2 send it a signal or would we need some sort of a conditional loop around the wait?
Also, how would the main thread have access to the exit status of the thread that signaled without explicitly calling pthread_join? Or, is there a way to get the thread_id of the thread that signaled so that the main thread may join it to retrieve its exit status?
If both threads run to completion before the main thread reaches the pthread_cond_wait(), then it will wait forever. Otherwise, the main thread will wait until one of the other threads signals the condition.
No, you cannot ask the condition who signalled it.
Your pthread condition has no memory; if no thread is waiting on the condition when it is signalled, the signal is not remembered. What matters is the state you manage, protected by the mutex. The pthread condition is simply the mechanism which allows the thread to wait if the state requires it.
So, whatever information you need to pass from the child threads to the parent, the trick is to do that under the mutex. In this case you want to pass the fact that the child has finished. Perhaps a simple bool, so the main thread:
pthread_mutex_lock(&mutex) ;
while (!t1_done && !t2_done)
pthread_cond_wait(&cond, &mutex) ;
pthread_mutex_unlock(&mutex) ;
And thread the first:
pthread_mutex_lock(&mutex) ;
t1_done = true ;
pthread_cond_signal(&cond) ;
pthread_mutex_unlock(&mutex) ;
...all pretty straightforward, really.

understanding pthread_cond_wait() and pthread_cond_signal()

I have this code as an example where two threads are created and then it looks like a pthread_cond_wait() is used to suspend that thread until it is ready to work again by the use of pthread_cond_signal(). My question is what if multiple threads are waiting at the same time? How will executing pthread_cond_signal() pick the correct thread to wake up? Is there a way to pick a specific thread to awake? Lets say i have a producer thread that puts customer orders into seperate queues where each queue is managed by a thread. If two consumer threads are suspend with wait() because they have nothing in their queue but then the producer thread only inserts an order into ONE of the consumer queues, how the heck do we differentiate? If this is not possible then what OTHER methods can i use to accomplish what i want?
Here is an example code because stackoverflow likes code... not that relevant:
Example
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include "check.h"
/* For safe condition variable usage, must use a boolean predicate and */
/* a mutex with the condition. */
int workToDo = 0;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#define NTHREADS 2
void *threadfunc(void *parm)
{
int rc;
while (1) {
/* Usually worker threads will loop on these operations */
rc = pthread_mutex_lock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
while (!workToDo) {
printf("Thread blocked\n");
rc = pthread_cond_wait(&cond, &mutex);
checkResults("pthread_cond_wait()\n", rc);
}
printf("Thread awake, finish work!\n");
/* Under protection of the lock, complete or remove the work */
/* from whatever worker queue we have. Here it is simply a flag */
workToDo = 0;
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
}
return NULL;
}
int main(int argc, char **argv)
{
int rc=0;
int i;
pthread_t threadid[NTHREADS];
printf("Enter Testcase - %s\n", argv[0]);
printf("Create %d threads\n", NTHREADS);
for(i=0; i<NTHREADS; ++i) {
rc = pthread_create(&threadid[i], NULL, threadfunc, NULL);
checkResults("pthread_create()\n", rc);
}
sleep(5); /* Sleep is not a very robust way to serialize threads */
for(i=0; i<5; ++i) {
printf("Wake up a worker, work to do...\n");
rc = pthread_mutex_lock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
/* In the real world, all the threads might be busy, and */
/* we would add work to a queue instead of simply using a flag */
/* In that case the boolean predicate might be some boolean */
/* statement like: if (the-queue-contains-work) */
if (workToDo) {
printf("Work already present, likely threads are busy\n");
}
workToDo = 1;
rc = pthread_cond_signal(&cond);
checkResults("pthread_cond_broadcast()\n", rc);
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_unlock()\n", rc);
sleep(5); /* Sleep is not a very robust way to serialize threads */
}
printf("Main completed\n");
exit(0);
return 0;
}
Output:
Enter Testcase - QP0WTEST/TPCOS0
Create 2 threads
Thread blocked
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Main completed
In practical terms, only one thread is awakened and you can't control which one it is.
(pthread_cond_signal wakes up at least one thread waiting on the given condition variable, and the thread chosen is determined by scheduling policy.)
In your case, you need to reconsider what the "condition" represented by your condition variable (condvar) means.
If the condvar truly means "a producer has added an item to one of several queues, each of which has a dedicated consumer," then you should pthread_cond_broadcast to awaken each queue's consumer and let the awakened threads figure out if there is work to do. Alternatively, you might recast the condition as "a producer has added an item to this queue, which has a dedicated consumer," and use one condvar per queue.

Resources