37 for (next = alarm_list; next != NULL; next = next->link)

38 printf ('%d(%d)['%s'] ', next->time,

39 next->time - time (NULL), next->message);

40 printf ('] ');

41 #endif

42 /*

43 * Wake the alarm thread if it is not busy (that is, if

44 * current_alarm is 0, signifying that it's waiting for

45 * work), or if the new alarm comes before the one on

46 * which the alarm thread is waiting.

47 */

48 if (current_alarm == 0 || alarm->time < current_alarm) {

49 current_alarm = alarm->time;

50 status = pthread_cond_signal (&alarm_cond);

51 if (status != 0)

52 err_abort (status, 'Signal cond');

53 }

54 }

Part 3 shows the alarm_thread function, the start function for the 'alarm server' thread. The general structure of alarm_thread is very much like the alarm_thread in alarm_mutex.c. The differences are due to the addition of the condition variable.

26-31 If the alarm_list is empty, alarm_mutex.c could do nothing but sleep anyway, so that main would be able to process a new command. The result was that it could not see a new alarm request for at least a full second. Now, alarm_thread instead waits on the alarm_cond condition variable, with no timeout. It will 'sleep' until you enter a new alarm command, and then main will be able to awaken it immediately. Setting current_alarm to 0 tells main that alarm_thread is idle. Remember that pthread_cond_wait unlocks the mutex before waiting, and relocks the mutex before returning to the caller.

35 The new variable expired is initialized to 0; it will be set to 1 later if the timed condition wait expires. This makes it a little easier to decide whether to print the current alarm's message at the bottom of the loop.

36-42 If the alarm we've just removed from the list hasn't already expired, then we need to wait for it. Because we're using a timed condition wait, which requires a POSIX.1b struct timespec, rather than the simple integer time required by sleep, we convert the expiration time. This is easy, because a struct timespec has two members—tv_sec is the number of seconds since the Epoch, which is exactly what we already have from the time function, and tv_nsec is an additional count of nanoseconds. We will just set tv_nsec to 0, since we have no need of the greater resolution.

43 Record the expiration time in the current_alarm variable so that main can determine whether to signal alarm_cond when a new alarm is added.

44-53 Wait until either the current alarm has expired, or main requests that alarm_ thread look for a new, earlier alarm. Notice that the predicate test is split here, for convenience. The expression in the while statement is only half the predicate, detecting that main has changed current_alarm by inserting an earlier timer. When the timed wait returns ETIMEDOUT, indicating that the current alarm has expired, we exit the while loop with a break statement at line 49.

54-55 If the while loop exited when the current alarm had not expired, main must have asked alarm_thread to process an earlier alarm. Make sure the current alarm isn't lost by reinserting it onto the list.

57 If we remove from alarm_list an alarm that has already expired, just set the expired variable to 1 to ensure that the message is printed.

¦ alarm_cond.c part 3 alarm_routine

1 /*

2 * The alarm thread's start routine.

3 */

4 void *alarm_thread (void *arg)

5 {

6 alarm_t *alarm;

7 struct timespec cond_time;

8 time_t now;

9 int status, expired;

10

11 /*

12 * Loop forever, processing commands. The alarm thread will

13 * be disintegrated when the process exits. Lock the mutex

14 * at the start — it will be unlocked during condition

15 * waits, so the main thread can insert alarms.

16 */

17 status = pthread_mutex_lock (&alarm_mutex);

18 if (status != 0)

19  err_abort (status, 'Lock mutex');

20 while (1) {

21 /*

22 * If the alarm list is empty, wait until an alarm is

23 * added. Setting current_alarm to 0 informs the insert

24 * routine that the thread is not busy.

25 */

26  current_alarm = 0;

27  while (alarm_list == NULL) {

28  status = pthread_cond_wait (&alarm_cond, &alarm_mutex);

29  if (status != 0)

30  err_abort (status, 'Wait on cond');

31  }

32  alarm = alarm_list;

33  alarm_list = alarm->link;

34  now = time (NULL);

35  expired = 0;

36  if (alarm->time > now) {

37 #ifdef DEBUG

38  printf ('[waiting: %d(%d)'%s'] ', alarm->time,

39  alarm->time - time (NULL), alarm->message);

40 #endif

41  cond_time.tv_sec = alarm->time;

42  cond_time.tv_nsec = 0;

43  current_alarm = alarm->time;

44  while (current_alarm == alarm->time) {

45  status = pthread_cond_timedwait (

46  &alarm_cond, &alarm_mutex, &cond_time);

47  if (Status == ETIMEDOUT) {

48  expired = 1;

49  break;

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

0

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

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