Главная страница Межпроцессное взаимодействие (состязание) Для систем обмена сообщениями также важен вопрос названий процессов. Необходимо однозначно определять процесс, указанный в запросе 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. Время обеда на факультете философии
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |