It is equally important that you test the predicate again when the thread wakes up. You should always wait for a condition variable in a loop, to protect against program errors, multiprocessor races, and spurious wakeups. The following short program, cond.c, shows how to wait on a condition variable. Proper predicate loops are also shown in all of the examples in this book that use condition variables, for example, alarm_cond.c in Section 3.3.4.
20-37 The wait_thread sleeps for a short time to allow the main thread to reach its condition wait before waking it, sets the shared predicate (data.value), and then signals the condition variable. The amount of time for which wait_thread will sleep is controlled by the hibernation variable, which defaults to one second.
51-52 If the program was run with an argument, interpret the argument as an integer value, which is stored in hibernation. This controls the amount of time for which wait.thread will sleep before signaling the condition variable.
68-83 The main thread calls pthread_cond_timedwait to wait for up to two seconds (from the current time). If hibernation has been set to a value of greater than two seconds, the condition wait will time out, returning ETIMEDOUT. If hibernation has been set to two, the main thread and wait_thread race, and, in principle, the result could differ each time you run the program. If hibernation is set to a value less than two, the condition wait should not time out.
■ cond.c
1 #include
2 #include
3 #include "errors.h" 4
5 typedef struct my_struct_tag {
6 pthread_mutex_t mutex;
7 pthread_cond_t cond;
8 int value;
9 } my_struct_t;
10
11 my_struct_t data = {
12 PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
13
14 int hibernation = 1; /* Default to 1 second */
15
16 /*
17 * Thread start routine. It will set the main thread's predicate
18 * and signal the condition variable.
19 */
20 void *
21 wait_thread (void *arg)
22 {
23 int status;
24
25 sleep (hibernation);
26 status = pthread_mutex_lock (&data.mutex);
27 if (status != 0)
28 err_abort (status, "Lock mutex");
29 data.value = 1; /* Set predicate */
30 status = pthread_cond_signal (&data.cond);
31 if (status != 0)
32 err_abort (status, "Signal condition");
33 status = pthread_mutex_unlock (&data.mutex);
34 if (status != 0)
35 err_abort (status, "Unlock mutex");
36 return NULL;
37 }
/* Protects access to value */ /* Signals change to value */ /* Access protected by mutex */
38
39 int main (int argc, char *argv[])
40 {
41 int status;
42 pthread_t wait_thread_id;
43 struct timespec timeout;
44
45 /*
46 * If an argument is specified, interpret it as the number
47 * of seconds for wait_thread to sleep before signaling the
48 * condition variable. You can play with this to see the
49 * condition wait below time out or wake normally.
50 */
51 if (argc > 1)
52 hibernation = atoi (argv[l]);
53
54 /*
55 * Create wait_thread.
56 */
57 status = pthread_create (
58 &wait_thread_id, NULL, wait_thread, NULL);
59 if (status != 0)
60 err_abort (status, "Create wait thread");
61
62 /*
63 * Wait on the condition variable for 2 seconds, or until
64 * signaled by the wait_thread. Normally, wait_thread
65 * should signal. If you raise "hibernation" above 2
66 * seconds, it will time out.
67 */