same associated mutex. Pthreads does not allow thread 1, for example, to wait on condition variable A specifying mutex A while thread 2 waits on condition variable A specifying mutex B. It is, however, perfectly reasonable for thread 1 to wait on condition variable A specifying mutex A while thread 2 waits on condition variable B specifying mutex A. That is, each condition variable must be associated, at any given time, with only one mutex—but a mutex may have any number of condition variables associated with it.

It is important that you test the predicate after locking the appropriate mutex and before waiting on the condition variable. If a thread signals or broadcasts a condition variable while no threads are waiting, nothing happens. If some other thread calls pthread_cond_wait right after that, it will keep waiting regardless of the fact that the condition variable was just signaled, which means that if a thread waits when it doesn't have to, it may never wake up. Because the mutex remains locked until the thread is blocked on the condition variable, the predicate cannot become set between the predicate test and the wait—the mutex is locked and no other thread can change the shared data, including the predicate.

Always test your predicate; and then test it again!

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 <pthread.h>

2 #include <time.h>

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 */

68 timeout.tv_sec = time (NULL) + 2;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату