Conditional wait and signal in multi-threading

Hye! I saw this code on geeks for geeks. But I am not able to fully get it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  // C program to implement cond(), signal() 
// and wait() functions 
#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 

// Declaration of thread condition variable 
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; 

// declaring mutex 
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 

int done = 1; 

// Thread function 
void* foo() 
{ 

	// acquire a lock 
	pthread_mutex_lock(&lock); 
	if (done == 1) { 

		// let's wait on conition variable cond1 
		done = 2; 
		printf("Waiting on condition variable cond1\n"); 
		pthread_cond_wait(&cond1, &lock); 
	} 
	else { 

		// Let's signal condition variable cond1 
		printf("Signaling condition variable cond1\n"); 
		pthread_cond_signal(&cond1); 
	} 

	// release lock 
	pthread_mutex_unlock(&lock); 

	printf("Returning thread\n"); 

	return NULL; 
} 

// Driver code 
int main() 
{ 
	pthread_t tid1, tid2; 

	// Create thread 1 
	pthread_create(&tid1, NULL, foo, NULL); 

	// sleep for 1 sec so that thread 1 
	// would get a chance to run first 
	sleep(1); 

	// Create thread 2 
	pthread_create(&tid2, NULL, foo, NULL); 

	// wait for the completion of thread 2 
	pthread_join(tid2, NULL); 

	return 0; 
} 


The basic concept which I want to understand is how a Thread should not continue its work until another thread finishes its work. But I am not able to identify this concept in this code.


This is what I know so far:


1) pthread_create(&tid1, NULL, foo, NULL);
This means that a thread is created for the function "foo" to get executed. We can say that thread is a Box, inside which foo is there which will decide the operation.
2) Foo execution starts with respect to thread 1!
pthread_mutex_lock(&lock) : A lock is acquired

3) If condition (I am not getting this)

if (done == 1):
I think this means that if thread 1 has completed its work then send a signal to someone who is waiting for this condition : pthread_cond_wait(&cond1, &lock);

else:
If work hasn't been done than send a signal to wake up.

Now my question is: To whom it is sending these signal?? Cuz thread 2 is not yet in the scene.

4) sleep(1) : Why we are setting it to sleep when pthread_cond_wait(&cond1, &lock)itself is a sleep condition for the thread.

Same goes with thread 2. I am not able to link the concept.




The code is not very good.

main sleeps for 1 second to ensure that thread 1 starts running and gets to the pthread_cond_wait before thread 2 starts..

'done' just ensures that thread 1 runs the first block of code (the if block) and thread 2 runs the second block (the else block). It would be better to have two different functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// gcc -std=c11 -Wall -W pthread01.c -lpthread

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void* foo() {
    pthread_mutex_lock(&lock);
    printf("Waiting on condition variable cond1\n");
    pthread_cond_wait(&cond1, &lock);
    pthread_mutex_unlock(&lock);
    printf("Returning from foo\n");
    return NULL;
}

void* bar() {
    pthread_mutex_lock(&lock);
    printf("Signaling condition variable cond1\n");
    pthread_cond_signal(&cond1);
    pthread_mutex_unlock(&lock);
    printf("Returning from bar\n");
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, foo, NULL);
    sleep(1);
    pthread_create(&t2, NULL, bar, NULL);
    pthread_join(t2, NULL);
    pthread_join(t1, NULL);
    return 0;
}

t1: created and starts running foo
main: sleeps for 1 second to ensure t1 starts running and
      gets to the cond_wait before t2 started
t1: locks the mutex
t1: waits on condition variable, associating the mutex with
    the condition variable and unlocking the mutex
t2: created and starts running bar
t2: locks the mutex
t2: signals the condition
t2: unlocks the mutex, allows thread 1 to run again
t2: keeps running
t2: prints "returning" and returns
t1: unlocks the mutex
t1: prints "returning" and returns
main: joins (waits on) t2
main: joins (waits on) t1

The last couple of steps of t2 and t1 above could occur in any order, or simultaneously.
Last edited on
t1: created and starts running foo
main: sleeps for 1 second to ensure t1 starts running and
gets to the cond_wait before t2 started
t1: locks the mutex
t1: waits on condition variable, associating the mutex with
the condition variable and unlocking the mutex
WHY foo didn't execute completely here?

t2: created and starts running bar
t2: locks the mutex
t2: signals the condition

Signaling wakes up the thread which is waiting for that cond.

t2: unlocks the mutex, allows thread 1 to run again

How did it allow for thread 1 to run again. Is it because of unlocking the mutex or is it because it sent a signal?

t2: keeps running
So t1 and t2 and running simultaneously now?

t2: prints "returning" and returns
t1: unlocks the mutex
t1: prints "returning" and returns
main: joins (waits on) t2
main: joins (waits on) t1
Topic archived. No new replies allowed.