转自:http://stackoverflow.com/questions/16819169/why-does-pthread-cond-signal-not-work#
I am currently learing all around POSIX threads (pthread). I now have created a simple program which increased a shared value by 7 until above 10000 then it should signal a condition to the next thread which decreases it by 3 until under 1000. At last it should divide the result through 2 and main should output the result. |
my code
pthread_t threads[3]; pthread_cond_t cond_a, cond_b; pthread_mutex_t mutex; int counter; void * worker_one(); void * worker_two(); void * worker_three(); int main(int argv, const char ** argc) { counter = 0; pthread_cond_init(&cond_a, NULL); pthread_cond_init(&cond_b, NULL); pthread_mutex_init(&mutex, NULL); pthread_create(&threads[0], NULL, worker_one, NULL); pthread_create(&threads[1], NULL, worker_two, NULL); pthread_create(&threads[2], NULL, worker_three, NULL); pthread_join(threads[0], NULL); pthread_join(threads[1], NULL); pthread_join(threads[2], NULL); printf("Value started at %d and ends with %d. ", 0, counter); return 0; } void * worker_one() { printf("Worker one started. "); pthread_mutex_lock(&mutex); printf("Worker one starting work. "); while (counter < 10000) { counter += 7; } pthread_cond_signal(&cond_a); printf("Worker one finished work with: %d. ", counter); pthread_mutex_unlock(&mutex); pthread_exit(NULL); } void * worker_two() { printf("Worker two started. "); pthread_mutex_lock(&mutex); pthread_cond_wait(&cond_a, &mutex); printf("Worker two starting work. "); while (counter > 1000) counter -= 3; printf("Worker two finished work with: %d. ", counter); pthread_cond_signal(&cond_b); pthread_mutex_unlock(&mutex); sleep(1); pthread_exit(NULL); } void * worker_three() { printf("Worker three started. "); pthread_mutex_lock(&mutex); pthread_cond_wait(&cond_b, &mutex); printf("Worker three starting work. "); counter /= 2; printf("Worker three finished work with: %d. ", counter); pthread_mutex_unlock(&mutex); pthread_exit(NULL); }
For some reason the whole execution hangs around the first thread. The signal is also fired but thread two does not react.
Can somebody tell me what I am doing wrong?
|
Could somebody tell me why down vote? – bodokaiser May 29 '13 at 16:23
|
||
|
I've moved the code from gist to SO. Don't just link to code on an external site, please include relevant code in the question. – user7116 May 29 '13 at 16:25
|
||
|
ok did not knew anything about this – bodokaiser May 29 '13 at 16:25
|
6 down vote accepted
I have answered a similar question here: pthread condition variables on Linux, odd behaviour. The problem is that you wait before even testing the condition you want to wait for is true. What happens is that thread 1 signals before thread 2 is waiting, therefore the signal is lost and thread 2 will be waiting forever. In order to avoid this, first test what you want to wait for, then wait only if it's not here. EDIT: Ok, here is a possible solution with only one mutex and one condtion (untested) Thread 1: |
pthread_mutex_lock(&mutex); while(thread_1_should_work == false){ // wait until the condition is satisfied pthread_cond_wait(&cond, &mutex); } //at this point, we owe the mutex and we know thread_1_should_work is true; // do work thread_1_shoudl_work = false; thread_2_should_work = true; pthread_cond_broadcast(&cond); //wake up any waiting thread (if it's not their turn, they'll call wait again) pthread_mutex_unlock(&mutex);
@bodokaiser: you'll have to make up a variable, but a simple boolean flag will do. Spurious wakeups are a reality unfortunately. – user7116 May 29 '13 at 16:35
|
|
@sixlettervariables so the main idea of conditions are just some more specific mutex signaling (with out the actual locking). Is this correct? – bodokaiser May 29 '13 at 16:36
|
|
Yes, in your case is thread_is_working flag would work (except that it has more than 6 letters :) I think the answer that the linked answer can help. – Ben May 29 '13 at 16:38
|
|
Actually, wait() releases the mutex and yield the thread atomically so that nothing happens while the thread is being yield. – Ben May 29 '13 at 16:41
|