Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 [ 131 ] 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

Листинг 15.22 (продолжение)

5 return; /* просто прерываем door call() */

6 }

7 int

8 mainCint argc. char **argv)

10 int fd;

11 long ival. oval;

12 door arg t arg;

13 if (argc != 3)

14 err quit( usage: clientintr2 <server-pathname> <integer-value> );

15 fd = Open(argv[l]. 0 RDWR): /* открываем дверь */

16 /* подготовка аргументов и указателя на результат */

17 ival. = atoi(argv[2]);

18 arg .data ptr = (char *) &ival; /* аргументы */

19 arg.data size = sizeof(long); /* размер аргументов */

20 arg.descjtr = NULL:

21 arg.desc num = 0:

22 arg.rbuf = (char *) &oval; /* данные */

23 arg.rsize = sizeof(long): /* размер данных */

24 Signal(SIGCHLD. sig chld):

25 if (ForkO == 0) {

26 sleep(2); /* дочерний процесс */

27 exitCO): /* отправка SIGCHLD */ 2B }

29 /* вызов процедуры сервера и вывод результата */

30 Door call(fd. &arg);

31 printfCresult: ld\n . oval):

32 exitCO):

33 }

Клиенту будет возвращена та же ошибка, что и при досрочном заверщении сервера - EINTR:

Solaris X clientintr2 /tmp/door2 22

door call error: Interrupted system call

Поэтому нужно блокировать все сигналы, которые могут прервать вызов с1оог са11. .

Идемпотентные и неидемпотентные процедуры

А что произойдет, если мы перехватим сигнал EINTR и вызовем процедуру сервера еще раз, поскольку мы знаем, что эта ошибка возникла из-за нашего собственного прерывания системного вызова перехваченным сигналом (SIGCHLD)? Это может привести к некоторым проблемам, как мы покажем ниже.

Изменим сервер так, чтобы он выводил идентификатор вызванного потока, делал паузу в 6 секунд и выводил идентификатор потока по завершении его. В листинге 15.23 приведен текст новой процедуры сервера.



Листинг 15.23. Процедура сервера, выводящая свой идентификатор потока дважды

doors/serverintr3.с

1 #lnclude unpipc.h

2 void

3 servprocCvoid *cookie. char *dataptr. s1ze t datasize.

4 door desc t *descptr, s1ze t ndesc)

6 long arg. result;

7 printfС thread id ld called\n . pr thread idCNULL));

8 sleepC6); /* даем клиенту возможность перехватить SIGCHLD */

9 arg = *CClong *) dataptr);

10 result = arg * arg;

11 printfС thread id *ld returning\n . pr thread idCNULL)):

12 Door returnCCchar *) &result, sizeofCresult), NULL. 0);

13 }

В листинге 15.24 приведен текст программы-клиента.

Листинг 15.24. Клиент, вызывающий door call еще раз, после перехвата E1NTR

doors/clientintr3.c

1 finclude unpipc.h

2 volatile sig atomic t caught sigchld;

3 void

4 sig chldCint signo)

5 {.

6 caught sigchld = 1;

7 return: /* прерываем вызов door callC) */

9 int

10 mainCint argc. char **argv)

11 {

12 int fd, rc;

13 long ival. oval:

14 door arg t arg;

15 if Cargc != 3)

16 err quitC usage; clientintr3 <server-pathname> <integer-value> );

17 fd = OpenCargvEl], 0 RDWR); /* открытие двери */

18 /* подготовка аргументов и указателя на результаты */

19 ival = atolCargv[2]);

20 arg.data ptr = Cchar *) &ival: /* аргументы */

21 arg.data size = sizeofClong); /* размер аргументов */

22 arg.desc ptr = NULL:

23 arg.desc num = 0:

24 arg.rbuf = Cchar *) &oval; /* возвращаемые данные */

25 arg.rsize = SizeofClong); /* размер данных */

26 SignalCSIGCHLD, sig chld): продолжение



Листинг 15.24 (продолжение)

27 1f (ForkO == 0) {

28 sleep(2): /* дочерний процесс */

29 ex1t(0): /* отправка SIGCHLD */

30 }

31 /* родительский процесс : вызов процедуры сервера и вывод результата */

32 for ( : : ) {

33 printfCcalUng door call\n );

34 1f ( (rc = door call(fd. &arg)) = 0)

35 break: /* успешное завершение */

36 if (errno == EINTR && caught sigchld) {

37 caught sigchld = 0:

38 continue; /* повторный вызов door call */

39 }

40 err sys( door call error );

41 }

42 printf( result: ld\n , oval):

43 exit(O):

44 }

2-8 Объявляем глобальную переменную caught sigchlcl, устанавливая ее в единицу при перехвате сигнала SIGCHLD. 31-42 Вызываем с1оог са11 в цикле, пока он не завершится успешно.

Глядя на выводимые клиентом результаты, мы можем подумать, что все в порядке:

Solaris X clientintr3 /tmp/door3 33

calling door call calling door call result: 1089

Функция doorcal 1 вызывается в первый раз, обработчик сигнала срабатывает через 2 секунды после этого и переменной caught si gchl d присваивается значение 1. door cal 1 при этом возвращает ошибку EINTR и мы вызываем door cal 1 еще раз, Во второй раз процедура завершается успешно.

Посмотрев на выводимый сервером текст, мы увидим, что процедура сервера была вызвана дважды:

Solaris X serverintr3 /tmp/door3

thread id 4 called thread id 4 returning thread id 5 called thread id 5 returning

Когда клиент второй раз вызывает door cal 1, это приводит к запуску нового потока, вызывающего процедуру сервера еще раз. Если процедура сервера идем-потентна, проблем в такой ситуации не возникнет. Однако если она неидемпо-тентна, это может привести к ошибкам.

Термин идемпотентность по отношению к процедуре подразумевает, что процедура может быть вызвана произвольное число раз без возникновения ошибок. Наша процедура сервера, вычисляющая квадрат целого числа, идемпотент-на: мы получаем правильный результат вне зависимости от того, сколько раз мы ее вызовем. Другим примером является процедура, возвращающая дату и время. Хотя эта процедура и будет возвращать разную информацию при новых вызовах (поскольку дата и время меняются), это не вызовет проблем. Классическим при-



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 [ 131 ] 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.