...
Another way to solve the signal issue is to use a unique condition variable for each thread (maintaining all associated with a single mutex associated with it). In this case, the signal operation (cnd_signal()
) only wakes up the only thread that is waiting on it. This solution turns out to be more efficient than using cnd_broadcast()
, because only the desired thread is awakened.
NOTE: The condition predicate of the signaled thread must be true; otherwise, a deadlock can will occur.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> #include <threads.h> enum { NTHREADS = 5 }; mtx_t mutex; cnd_t cond[NTHREADS]; int run_step(void *t) { static int current_step = 0; int my_step = (int)t; if (thrd_success != mtx_lock(&mutex)) { /* Handle error condition. */ } printf("Thread %d has the lock\n", my_step); while (current_step != my_step) { printf("Thread %d is sleeping...\n", my_step); if (thrd_success != cnd_wait(&cond[my_step], &mutex)) { /* Handle error condition. */ } printf("Thread %d woke up\n", my_step); } /* Do processing... */ printf("Thread %d is processing...\n", my_step); current_step++; /* Signal next step thread. */ if ((my_step + 1) < NTHREADS) { if (thrd_success != cnd_signal(&cond[my_step + 1])) { /* Handle error condition */ } } printf("Thread %d is exiting...\n", my_step); if (thrd_success != mtx_unlock(&mutex)) { /* Handle error condition. */ } return 0; } int main(int argc, char** argv) { int i; thrd_t threads[NTHREADS]; int step[NTHREADS]; if (thrd_success != mtx_init(&mutex, mtx_plain)) { /* Handle error condition. */ } for (i = 0; i< NTHREADS; ++i) { if (thrd_success != cnd_init(&cond[i])) { /* Handle error condition. */ } } /* Create threads. */ for (i = 0; i < NTHREADS; ++i) { step[i] = i; if (thrd_success != thrd_create(&threads[i], run_step, (void *)step[i])) { /* Handle error condition. */ } } /* Wait for all threads to complete. */ for (i = NTHREADS - 1; i >= 0; --i) { if (thrd_success != thrd_join(threads[i], NULL)) { /* Handle error condition. */ } } mtx_destroy(&mutex); for (i = 0; i < NTHREADS; ++i) { cnd_destroy(&cond[i]); } return 0; } |
...
Risk Assessment
Signaling a single thread instead of all waiting threads can pose a threat to the liveness property of the system.
...