for example, clock_gettime, which is part of the POSIX. lb realtime standard. The additional realtime library is specified by the RTFLAGS variable, which is defined as RTFLAGS=-lrt on Digital UNIX, and as RTFLAGS=-lposix4 on Solaris.

On Solaris 2.5 systems, several of the examples require calls to thr_setcon-currency to ensure proper operation. This function causes Solaris to provide the process with additional concurrency. In a few cases, the example will not operate at all without this call, and in other cases, the example would fail to demonstrate some behavior.

1.5 Asynchronous programming, by example

'In one moment I've seen what has hitherto been Enveloped in absolute mystery, And without extra charge I will give you at large A Lesson in Natural History.'

Lewis Carroll, The Hunting of the Snark

This section demonstrates some basic asynchronous programming, using a simple program that does something vaguely useful, by pretending to be an alarm clock with a command interface for which you would not consider paying a dime in a store. But then, this book is about threads, not user interfaces, and the code that I need to show takes up quite enough space already.

The program prompts for input lines in a loop until it receives an error or end of file on stdin. On each line, the first nonblank token is interpreted as the number of seconds to wait, and the rest of the line (up to 64 characters) is a message that will be printed when the wait completes. I will offer two additional versions— one using multiple processes, and one using multiple threads. We'll use the three examples to compare the approaches.

1.5.1 The baseline, synchronous version

1 Include the header file errors.h, which includes standard headers like <unistd.h> and <stdio.h> and defines error reporting macros that are used throughout the examples in this book. We don't use the error reporting macros in this particular example, but consistency is nice, sometimes.

9-26 The 'baseline' version, alarm.c, is a synchronous alarm program with a single routine, main. Most of main is a loop, which processes simple commands until fgets returns a NULL (error or end of file). Each line is 'parsed' with sscanf to separate the number of seconds to wait (%d, the first sequence of digits) from the message string to print (%64 [^ ], the rest of the line, up to 64 characters excluding newline).

¦ alarm.c

1 #include 'errors.h' 2

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

4 {

5 int seconds;

6 char line[128];

7 char message[64]; 8

9 while (1) {

10 printf ('Alarm> ');

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

12 if (strlen (line) <= 1) continue; 13

14 /*

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

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

17 * separated from the seconds by whitespace.

18 */

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

20 &seconds, message) < 2) {

21 fprintf (stderr, 'Bad command ');

22 } else {

23 sleep (seconds);

24 printf ('(%d) %s ', seconds, message);

25 }

26 }

27 }

The problem with the program alarm.c is that only one alarm request can be active at a time. If you set an alarm to remind you to do something in 10 minutes (600 seconds), you can't decide to have it remind you of something else in 5 minutes. The program is doing something synchronously that you would probably like to be asynchronous.

1.5.2 A version using multiple processes

There are lots of ways to make this program asynchronous; for example, you could run more than one copy of the program. One way to run multiple copies is to fork a child process for each command, as shown in alarm_fork.c. The new version is asynchronous—you can enter commands at any time, and they will be carried out independently. It isn't much more complicated than the original, which is nice.

27-37 The main difference between alarm.c and alarm_fork.c is that instead of calling sleep directly, it uses fork to create a new child process, which then calls sleep (and, eventually, printf) asynchronously, while the parent process continues.

42-46 The primary complication in this version is the need to 'reap' any child processes that have terminated. If the program fails to do this, the system will save them all until the program terminates. The normal way to reap terminated child processes is to call one of the wait functions. In this case, we call waitpid, which allows the caller to specify the WNOHANG flag. The function will immediately reap one child process if any have terminated, or will immediately return with a process ID (pid) of 0. The parent process continues to reap terminated child processes until there are no more to reap. When the loop terminates, main loops back to line 13 to read a new command.

¦ alarm_fork.c

1 #include <sys/types.h>

2 #include <wait.h>

3 #include 'errors.h'

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

6 {

7 int status;

8 char line[128];

9 int seconds;

10 pid_t pid;

11 char message[64]; 12

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

0

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

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