Unexpected behavior while using condition variable multithread - c

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);
}

Related

why this code return unexpected result? (conditional variable)

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

unexpected behavior when using conditional variables (c, gcc)

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)

Single producer and multiple consumers

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.

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?

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