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

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

Глава 9

1. в зависимости от системы может потребоваться увеличивать счетчик до значений, больших 20, чтобы наблюдать ошибку.

2. Для отключения буферизации стандартного потока мы добавляем строку

setvbuf(stdout. NULL. JONBF. 0): к функции main перед циклом for. Это не должно ни на что влиять, поскольку вызов printf только один и строка завершается символом перевода. Обычно стандартный поток вывода буферизуется построчно, поэтому в любом случае один вызов printf превращается в один системный вызов write.

3. Заменим printf на

snprintfdine. sizeof(line), s: pid = *ld. seq# = M\n . argv[0], (long) pid, seqno); for (ptr = line; (c = *ptr++) != 0) putchar(c);

и объявим с как целое, а ptr - как char *. Если мы вызвали setvbuf для отключения буферизации стандартного потока вывода, библиотека будет делать системный вызов для вывода каждого символа. На это требуется больше времени, что дает ядру больше возможностей на переключение контекста между процессами. Такая программа должна давать больше ошибок.

4. Поскольку несколько процессов могут заблокировать на чтение одну и ту же область файла, в нашем примере это эквивалентно полному отсутствию блокировок.

5. Ничего не изменится, поскольку флаг отключения блокировки для дескриптора никак не влияет на работу рекомендательной блокировки fcntl. Блокирование процесса при вызове fcntl определяется типом команды: F SETLKW (которая блокируется всегда) или F SETLK (которая не блокируется никогда).

6. Программа 1 oopfcntl nonb работает как положено, поскольку, как мы показали в предыдущем примере, флаг отключения блокировки никак не влияет на блокировку fcntl. Однако этот флаг влияет на работу loopnonenonb, которая не пользуется блокировкой. Как говорилось в разделе 9.5, неблокируемый вызов write или read для файла с включенной обязательной блокировкой приводит к возврату ошибки EAGAIN. Мы увидим одно из следующих сообщений:

read error: Resource temporarily unavailable write error: Resource temporarily unavailable

и мы можем проверить, что это сообщение соответствует EAGAIN, выполнив

Solaris % grep Resource /usr/include/sys/errno.h

#define EAGAIN U /* Resource temporarily unavailable */

7. В Solaris 2.6 обязательная блокировка увеличивает время работы на 16%, а время процессора - на 20%. Пользовательское время процессора остается прежним, поскольку проверка осуществляется в ядре, а не в процессе.

8. Блокировки выдаются процессам, а не потокам.

9. Если бы работала другая копия демона, а мы открыли бы файл с флагом 0 TRUNC, это привело бы к удалению идентификатора процесса из файла. Мы не имеем



права укорачивать файл, пока не убедимся, что данная копия является единственной.

10. Лучше использовать SEEK SET. Проблема с SEEK CUR заключается в том, что этот вариант зависит от текущего положения в файле, устанавливаемого Iseek. Однако если мы вызываем 1 seek, а потом fcntl, мы делаем одну операцию в два вызова и существует вероятность, что другой процесс в промежутке между вызовами изменит текущий сдвиг вызовом 1 seek. Вспомните, что все потоки используют общие дескрипторы. Аналогично, если указать SEEK END, другой процесс может дописать данные к файлу, прежде чем мы получим блокировку, и тогда она уже не будет распространяться на весь файл.

Глава 10

i=0 у производителя

7-J у производителя

начало следутего цикла, но места больше нет. поэтому происходит переключение контекста 1-0

1. Вот результат работы в Solaris 2.6:

Solaris % deadlock 100

prod: calling seni wait(nenpty)

prod: got seni wait(nempty)

prod: calling sem wait(mutex)

prod: got seni wait(mutex), storing 0

prod: calling sem wait(nempty)

prod; got seni wait(nempty)

prod: calling sem wait(mutex)

prod: got sem wait(mutex). storing 1

prod: calling sem wait(nempty)

cons: calling sem wait(mutex) cons: got sem wait(mutex) cons: calling sem wait(nstored) cons: got sem wait(nstored) cons: fetched 0 cons: calling sem wait(mutex) cons: got sem wait(mutex) cons: calling sem wait(nstored) cons: got sem wait(nstored) cons: fetched 1 cons: calling sem wait(mutex) cons: got sem wait(mutex) cons: calling sem wait(nstored) prod: got sem wait(nempty)

prod: calling sem wait(mutex) a здесь блокируется производитель.

2. Это не вызывает проблем с учетом правил, которые были указаны при описании sem open: если семафор уже существует, он не инициализируется. Поэтому только первая из четырех программ, вызывающих sem open, инициализирует семафор.

3. Это проблема. Семафор автоматически закрывается при завершении процесса, но значение его не изменяется. Это не дает другим программам получить блокировку, и все зависает.

4. Если мы не инициализируем дескрипторы значением -1, их значение оказывается неизвестным, поскольку mal 1 ос не инициализирует выделяемую память.

здесь блокируется потребитель. Навсегда.



Поэтому если один из вызовов open возвращает ошибку, вызовы с1 ose под меткой error могут закрыть какой-нибудь используемый процессом дескриптор. Инициализируя дескрипторы значением -1, мы можем быть уверены, что вызовы с1 ose не дадут результата (помимо возвращения игнорируемой ошибки), если дескриптор еще не был открыт.

5. Существует вероятность, что close будет вызвана для нормального дескриптора и вернет ошибку, изменив значение еггпо. Поэтому нам нужно сохранить это значение в другой переменной, чтобы оно не изменилось из-за побочного эффекта.

6. В этой функции ситуация гонок не возникает, поскольку mkfifo возвращает ошибку, если канал уже существует. Если два процесса вызывают эту функцию одновременно, канал FIFO создается только один раз. Второй вызов mkf i f о приведет к возврату EEXIST.

7. В программе из листинга 10.22 ситуация гонок, описанная в связи с листингом 10.28, не возникает, поскольку инициализация семафора осуществляется записью данных в канал. Если процесс, создавший канал, приостанавливается ядром после создания, но перед записью данных, второй процесс откроет этот канал и заблокируется в вызове semwait, поскольку только что созданный канал будет пуст (пока первый процесс не поместит в него данные).

8. В листинге Г.6 приведена тестовая программа. Реализации Solaris 2.6 и Digital Unix 4.0В обнаруживают прерывание перехватываемым сигналом и возвращают ошибку EINTR.

Листинг Г.6. Возвращает ли sem wait ошибку EINTR?

pxsem/testeintr.c

1 #include unpipc.h

2 #define NAME testeintr

3 static void sig alrm(int);

4 int

5 maindnt argc. char **argv)

7 sem t *seml, sem2;

8 /* именованный семафор */

9 sem unlink(Px ipc name(NAME)):

10 semi = Sem open(Px ipc name(NAME), 0 RDWR 0 CREAT 0 EXCL,

11 FILE MODE. 0);

12 Signal(SIGALRM, sig alrm):

13 alarm(2):

14 if (sem wait(seml) == 0)

15 prTntf( sem wait returned 0?\n );

16 else

17 err ret( sem wait error ):

18 Sem close(seml):

19 /* размещаемый в памяти семафор */



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.
Копирование материалов разрешено исключительно при условии цититирования.