Главная страница  Межпроцессное взаимодействие (состязание) 

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 187

Для систем обмена сообщениями также важен вопрос названий процессов. Необходимо однозначно определять процесс, указанный в запросе send или receive. Кроме того, встает вопрос аутентификации: каким образом клиент может определить, что он взаимодействует с настоящим файловым сервером, а не с самозванцем?

Помимо этого существуют конструктивные проблемы, существенные при расположении отправителя и получателя на одном компьютере. Одной из таких проблем является производительность. Копирование сообщений из одного процесса в другой происходит гораздо медленнее, чем операция на семафоре или вход в монитор. Было проведено множество исследований с целью увеличения эффективности передачи сообщений. В [10], например, предлагалось ограничивать размер сообщения до размеров регистра и передавать сообщения через регистры.

Решение проблемы производителя и потребителя путем передачи сообщений

Теперь рассмотрим решение проблемы производителя и потребителя посредством передачи сообщений и без использования общей памяти. Решение представлено в листинге 2.7. Мы предполагаем, что все сообщения имеют одинаковый размер, и сообщения, которые посланы, но еще не получены, автоматически помещаются операционной системой в буфер. В этом решении используются N сообщений, по аналогии с N сегментами в буфере. Потребитель начинает с того, что посылает производителю N пустых сообщений. Как только у производителя оказывается элемент данных, который он может предоставить потребителю, он берет пустое сообщение и отсылает назад полное. Таким образом, общее число сообщений в системе постоянно, и их можно хранить в заранее отведенной области памяти.

Листинг 2.7. Решение проблемы производителя и потребителя с использованием N сообщений

#define N 100 /* Количество сегментов в буфере */

void producerCvoid)

int item;

message m; /* Буфер для сообщений */

while (TRUE) {

item = produce item(); /* Сформировать нечто, чтобы заполнить /* буфер */

receive(consumer. &m); /* Ожидание прибытия пустого сообщения */ build message(&m. item); /* Сформировать сообщение для отправки */ sendCconsumer. &m); /* Отослать элемент потребителю*/

void consumer(void) {

int item, i; message m;

for (i = 0; i < N; i++) {

sendCproducer. &m);



} /* Отослать Н пустых сообщений */

while (TRUE) {

receive(producer, &m): /* Получить сообщение с элементом */ item = extractjtem(&m): /* Извлечь элемент из сообщения */ send(producer. &m): /* Отослать пустое сообщение */ consume item(item): /* Обработка элемента */

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

Передача сообщений реализуется по-разному. Рассмотрим способ адресации сообщений. Можно присвоить каждому из процессов уникальный адрес и адресовать сообщение непосредственно процессам. Другой подход состоит в использовании новой структуры данных, называемой почтовым ти/гком. Почтовый ящик - это буфер для определенного количества сообщений, тип которых задается при создании ящика. При использовании почтовых ящиков в качестве параметров адреса send и receive задаются почтовые ящики, а не процессы. Если процесс пытается послать сообщение в переполненный почтовый ящик, ему приходится подождать, пока хотя бы одно сообщение не будет оттуда удалено.

В задаче производителя и потребителя оба они создадут почтовые ящики, достаточно большие, чтобы хранить N сообщений. Производитель будет посылать сообщения с данными в почтовый ящик потребителя, а потребитель станет отправлять пустые сообщения в почтовый ящик производителя. В случае почтовых ящиков способ буферизации очевиден: в почтовом ящике получателя хранятся сообщения, которые были посланы процессу-получателю, но еще не получены.

Другой крайностью при использовании почтовых ящиков является принципиальное отсутствие буферизации. При таком подходе, если send выполняется раньше, чем receive, процесс-отправитель блокируется до выполнения receive, когда сообщение может быть напрямую скопировано от отправителя к получателю без промежуточной буферизации. Если receive выполняется раньше, чем send, процесс-получатель блокируется до выполнения send. Этот метод часто называется рандеву, он легче реализуется, чем схема буферизации сообщений, но менее гибок, поскольку отправитель и получатель должны работать в режиме жесткой синхронизации.

В операционной системе MINIX взаимодействие между процессами происходит посредством каналов, которые по своей сути являются почтовыми ящиками. Единственная разница между механизмом каналов и настоящими почтовыми ящиками в том, что в каналах нет разграничения сообщений. Другими словами, если источник поместит в канал 10 сообщений по 100 байт, а приемник прочитает 1000 байт, то он сразу прочитает все О сообщений. Конечно, если существует договоренность всегда использовать сообщения одного и того же размера, то подобных проблем не возникает. Кроме того, можно ввести специальный символ



для разделения сообщений (скажем, перевод строки). Например, в процессах, образующих ОС MINIX, для обмена информацией применена схема с сообщениями фиксированного размера.

2.3. Классические проблемы межпроцессного взаимодействия

Литература по операционным системам охватывает множество интересных проблем, которые широко обсуждались и анализировались с применением различных методов синхронизации. В этом разделе мы рассмотрим три наиболее известных проблемы.

2.3.1. Проблема обедающих философов

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


Рис. 2.7. Время обеда на факультете философии



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 187

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