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

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

solans % semwait /test2

pid 4133 has semaphore, value = 0

нажимаем клавишу прерывания выполнения Solaris % semgetvalue /test2 value = 0

Посмотрим теперь, как меняется значение семафора в этой реализации при появлении новых процессов, ожидающих изменения значения семафора: Solaris % semgetvalue /test2

value = О значение сохранилось с конца предыдущего примера

Solaris % semwait /test2 & запуск в фоновом режиме [1]4257 программа блокируется

Solaris % semgetvalue /test2

value = 0 в зтой реализации отрицательные значения не используются

Solaris % serrwait /test2 & еще один фоновый процесс [2]4263

Solaris % semgetvalue /test2

value - О и для двух ожидающих процессов значение остается нулевым

Solaris % sempost /test2 выполняем операцию post

pid 4257 has semaphore, value = 0 вывод программы semait value = 0

Solaris % sempost /test2

pid 4263 has semaphore, value = 0 вывод программы semait

value = 0

Можно заметить отличие по сравнению с результатами выполнения той же последовательности команд в Digital Unix 4.0В: после изменения значения семафора управление сразу же передается ожидающему изменения семафора процессу.

10.6. Задача производителей и потребителей

в разделе 7.3 мы описали суть задачи производителей и потребителей и привели несколько возможных ее рещений, в которых несколько потоков-производителей заполняли массив, который обрабатывался одним потоком-потребителем.

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

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

Расширим постановку задачи производителей и потребителей, используя общий буфер в качестве циклического: заполнив последнее поле, производитель (buff [NBUFF-1]) возвращается к его началу и заполняет первое поле (buff [0]), и потребитель действует таким же образом. Возникает еще одно требование к синхронизации: потребитель не должен опережать производителя. Мы все еще пред-



полагаем, что производитель и потребитель представляют собой отдельные потоки одного процесса, но они также могут быть и просто отдельными процессами, если мы сможем создать для них общий буфер (например, используя разделяемую память, часть 4).

При использовании общего буфера в качестве циклического код должен удовлетворять трем требованиям:

1. Потребитель не должен пытаться извлечь объект из буфера, если буфер пуст.

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

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

Наще рещение использует три семафора:

1. Бинарный семафор с именем mutex защищает критические области кода: помещение данных в буфер (для производителя) и изъятие данных из буфера (для потребителя). Бинарный семафор, используемый в качестве взаимного исключения, инициализируется единицей. (Конечно, мы могли бы воспользоваться и обычным взаимным исключением вместо двоичного семафора, См. упражнение 10.10.)

2. Семафор-счетчик с именем nempty подсчитывает количество свободных полей в буфере. Он инициализируется значением, равным объему буфера (NBUFF).

3. Семафор-счетчик с именем nstored подсчитывает количество заполненных полей в буфере. Он инициализируется нулем, поскольку изначально буфер пуст.

На рис. 10.7 показано состояние буфера и двух семафоров-счетчиков после заверщения инициализации. Неиспользуемые элементы массива выделены темным.

buff [0] buff [1] buff [2] buff [3]

buff [NBUFF-1]:

nempty: nstored:

NBUFF

Рис. 10.7. Состояние буфера и двух семафоров-счетчиков после инициализации



В нашем примере производитель помещает в буфер целые числа от О до NLOOP -1 (buff [0] = О, buff [1] = 1), работая с ним как с циклическим. Потребитель считывает эти числа и проверяет их правильность, выводя сообщения об ошибках в стандартный поток вывода.

На рис. 10.8 изображено состояние буфера и семафоров-счетчиков после помещения в буфер трех элементов, но до изъятия их потребителем.

производитель помещает в буфер три элемента

-> bufT[0] -> bufT[1]; -> buff [2] buff[3];

buff [NBUFF-1]:

nempty: nstored:

NBUFF-3

Рис. 10.8. Буфер и семафоры после помещения в буфер трех элементов

Предположим, что потребитель изъял один элемент из буфера. Новое состояние изображено на рис. 10.9.

buff [NBUFF-1]:

buff [0]:

buffll]:

buff [2]:

buff [3]:

потребитель изымает 1 элемент из буфера

nempty: nstored:

NBUFF-2

Рис. 10.9. Буфер и семафоры после удаления первого элемента из буфера

В листинге 10.8 приведен текст функции main, которая создает три семафора, запускает два потока, ожидает их завершения и удаляет семафоры.

Листинг 10.8. Функция main для решения задачи производителей и потребителей с помощью семафоров

pxsem/prodconsl.c

1 linclude unpipc.h

2 Idefine NBUFF 10



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