24 * command. If the list is not empty, remove the first

25 * item. Compute the number of seconds to wait — if the

26 * result is less than 0 (the time has passed), then set

27 * the sleep_time to 0.

28 */

29 if (alarm == NULL)

30 sleep_time = 1;

31 else {

32 alarm_list = alarm->link;

33 now = time (NULL);

34 if (alarm->time <= now)

35  sleep_time = 0;

36 else

37  sleep_time = alarm->time - now;

38 #ifdef DEBUG

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

40 sleep_time, alarm->message);

41 #endif

42 }

43

44 /*

45 * Unlock the mutex before waiting, so that the main

46 * thread can lock it to insert a new alarm request. If

47 * the sleep_time is 0, then call sched_yield, giving

48 * the main thread a chance to run if it has been

49 * readied by user input, without delaying the message

50 * if there's no input.

51 */

52 status = pthread_mutex_unlock (&alarm_mutex);

53 if (status != 0)

54  err_abort (status, 'Unlock mutex');

55 if (sleep_time > 0)

56  sleep (sleep_time);

57 else

58  sched_yield ();

59

60 /*

61 * If a timer expired, print the message and free the

62 * structure.

63 */

64 if (alarm != NULL) {

65  printf ('(%d) %s ', alarm->seconds, alarm->message);

66  free (alarm);

67 }

68 }

69 }

And finally, the code for the main program for alarm_mutex.c. The basic structure is the same as all of the other versions of the alarm program that we've developed—a loop, reading simple commands from stdin and processing each in turn. This time, instead of waiting synchronously as in alarm.c, or creating a new asynchronous entity to process each alarm command as in alarm_fork.c and alarm_thread.c, each request is queued to a server thread, alarm_thread. As soon as main has queued the request, it is free to read the next command.

8-11 Create the server thread that will process all alarm requests. Although we don't use it, the thread's ID is returned in local variable thread.

13-28 Read and process a command, much as in any of the other versions of our alarm program. As in alarm_thread.c, the data is stored in a heap structure allocated by malloc.

30-32 The program needs to add the alarm request to alarm_list, which is shared by both alarm_thread and main. So we start by locking the mutex that synchronizes access to the shared data, alarm_mutex.

33 Because alarm_thread processes queued requests, serially, it has no way of knowing how much time has elapsed between reading the command and processing it. Therefore, the alarm structure includes the absolute time of the alarm expiration, which we calculate by adding the alarm interval, in seconds, to the

current number of seconds since the UNIX Epoch, as returned by the time function.

39-49 The alarms are sorted in order of expiration time on the alarm_list queue. The insertion code searches the queue until it finds the first entry with a time greater than or equal to the new alarm's time. The new entry is inserted preceding the located entry. Because alarm_list is a simple linked list, the traversal maintains a current entry pointer (this) and a pointer to the previous entry's link member, or to the alarm_list head pointer (last).

56-59 If no alarm with a time greater than or equal to the new alarm's time is found, then the new alarm is inserted at the end of the list. That is, if the alarm pointer is NULL on exit from the search loop (the last entry on the list always has a link pointer of NULL), the previous entry (or queue head) is made to point to the new entry.

¦ alarm_mutex.c part 3 main

1 int main (int argc, char *argv[])

2 {

3 int status;

4 char line[128];

5 alarm_t *alarm, **last, *next;

6 pthread_t thread;

7

8 status = pthread_create (

9 &thread, NULL, alarm_thread, NULL);

10 if (status != 0)

11 err_abort (status, 'Create alarm thread');

12 while (1) {

13  printf ('alarm> ');

14  if (fgets (line, sizeof (line), stdin) == NULL) exit (0);

15  if (strlen (line) <= 1) continue;

16  alarm = (alarm_t*)malloc (sizeof (alarm_t));

17  if (alarm == NULL)

18  errno_abort ('Allocate alarm');

19

20 /*

21 * Parse input line into seconds (%d) and a message

22 * (%64[^ ]), consisting of up to 64 characters

23 * separated from the seconds by whitespace.

24 */

25  if (sscanf (line, '%d %64[^ ]',

26  &alarm->seconds, alarm->message) < 2) {

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

0

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

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