Литмир - Электронная Библиотека
A
A

Строки 99–100 создают набор сигналов, представляющих

SIGCHLD
, а строка 102 устанавливает их в качестве маски сигналов процесса для программы.

Строки 104–109 создают пять порожденных процессов, каждый из которых засыпает на три секунды. По ходу дела они обновляют массив

kids
и переменную
nkids
.

Строка 111 дает затем потомкам шанс завершиться, заснув на еще больший промежуток времени. (Это не гарантирует, что порожденные процессы завершатся, но шансы довольно велики.)

Наконец, строки 113–114 выводят сообщение и приостанавливаются, заменив маску сигналов процесса, блокирующую

SIGCHLD
, пустой маской. Это дает возможность появиться сигналу
SIGCHLD
, что в свою очередь вызывает запуск обработчика сигнала. Вот что происходит:

$ <b>ch10-reap1</b> /* Запуск программы */

waiting for signal

Entered childhandler

  reaped process 23937

  reaped process 23938

  reaped process 23939

  reaped process 23940

  reaped process 23941

Exited childhandler

Обработчик сигнала собирает сведения о потомках за один проход.

Следующая программа,

ch10-reap2.c
, сходна с
ch10-reap1.c
. Разница в том, что она допускает появление сигнала
SIGCHLD
в любое время. Такое поведение увеличивает шанс получения более одного
SIGCHLD
, но не гарантирует это. В результате обработчик сигнала все равно должен быть готов обработать в цикле несколько потомков.

1  /* ch10-reap2.c — демонстрирует управление SIGCHLD, один сигнал на потомка */

2

   /* ...не изменившийся код пропущен... */

12

13 pid_t kids[MAX_KIDS];

14 size_t nkids = 0;

15 size_t kidsleft = 0; /* &lt;&lt;&lt; Добавлено */

16

 /* ...не изменившийся код пропущен... */

41

42 /* childhandler --- перехват SIGCHLD, опрос всех доступных потомков */

43

44 void childhandler(int sig)

45 {

46  int status, ret;

47  int i;

48  char buf[100];

49  static const char entered[] = &quot;Entered childhandler\n&quot;;

50  static const char exited[] = &quot;Exited childhandler\n&quot;;

51

52  write(1, entered, strlen(entered));

53  for (i = 0; i &lt; nkids; i++) {

54   if (kids[i] == NOT_USED)

55    continue;

56

57 retry:

58  if ((ret = waitpid(kids[i], &amp;status, WNOHANG)) == kids[i]) {

59   strcpy(buf, &quot;\treaped process &quot;);

60   strcat(buf, format_num(ret));

61   strcat(buf, &quot;\n&quot;);

62   write(1, buf, strlen(buf));

63   kids[i] = NOT_USED;

64   kidsleft--; /* &lt;&lt;&lt; Добавлено */

65  } else if (ret == 0) {

    /* ...не изменившийся код пропущен... */

80  write(1, exited, strlen(exited));

81 }

Это идентично предыдущей версии за тем исключением, что у нас есть новая переменная,

kidsleft
, указывающая, сколько имеется не опрошенных потомков. Строки 15 и 64 помечают новый код.

83  /* main --- установка относящейся к порожденным процессам сведений

       и сигналов, создание порожденных процессов */

84

85  int main(int argc, char **argv)

86  {

     /* ...не изменившийся код пропущен... */

100

101  sigemptyset(&amp;childset);

102  sigaddset(&amp;childset, SIGCHLD);

103

104  /* sigprocmask(SIG_SETMASK, &amp;childset, NULL); /* блокирование в коде main */

105

106  for (nkids = 0; nkids &lt; 5; nkids++) {

107   if ((kids[nkids] = fork()) == 0) {

108    sleep(3);

109    _exit(0);

110   }

111   kidsleft++; /* &lt;&lt;&lt; Added */

112  }

113

114  /* sleep(5); /* дать потомкам шанс завершиться */

115

116  while (kidsleft &gt; 0) { /* &lt;&lt;&lt; Добавлено */

117   printf(&quot;waiting for signals\n&quot;);

118   sigsuspend(&amp;emptyset);

119  } /* &lt;&lt;&lt; Добавлено */

120

121  return 0;

122 }

Здесь код также почти идентичен. Строки 104 и 114 закомментированы из предыдущей версии, а строки 111, 116 и 119 добавлены. Удивительно, при запуске поведение меняется в зависимости от версии ядра!

$ <b>uname -a</b> /* Отобразить версию системы */

Linux example1 2.4.20-8 #1 Thu Mar 13 17:54:28 EST 2003 i686 i686 i386 GNU/Linux

151
{"b":"576259","o":1}