
- •Лекція №8 Паралельні обчислення: семафори, монітори, повідомлення
- •8.1. Семафоры
- •8.1.1. Взаимные исключения
- •Листинг 8.2. Взаимоисключения с использованием семафоров
- •8.1.2. Задача “производителя-потребителя” ("писатель-читатель")
- •8.2. Мониторы
- •8.2.1. Мониторы с сигналами (мониторы Хоара)
- •8.2.2. Мониторы с оповещением и широковещанием
- •8.3.1. Синхронизация
- •8.3.2. Адресация
- •8.3.3. Формат сообщения
8.3.3. Формат сообщения
Формат сообщения зависит от преследуемых целей и от того, работает ли система передачи сообщений на одном компьютере или в распределенной системе. В ряде ОС разработчики предпочитают короткие сообщения фиксированной длины, что позволяет минимизировать обработку и уменьшить расходы памяти на их хранение. Однако более гибкий подход позволяет использовать сообщения переменной длины. На рис. 8.4 показан формат типичного сообщения переменной длины.
Тип сообщения |
Идентификатор получателя |
Идентификатор отправителя |
Длина сообщения |
Управляющая информация |
Содержание сообщения |
Рис. 8.4. Обобщенный формат сообщения
8.3.4. Взаимные исключения
В листинге 8.7 показан один из способов реализации взаимных исключений с использованием системы передачи сообщений. В данной программе предполагается использование блокирующего receive и неблокирующего send. Множество параллельно выполняющихся процессов совместно используют почтовый ящик mutex как для отправки сообщений, так и для их получения. Почтовый ящик после инициализации содержит единственное сообщение с пустым содержанием. Процесс, намеривающийся войти в критический раздел, сначала пытается получить сообщение. Если почтовый ящик пуст, процесс блокируется. Как только процесс получает сообщение, он тут же выполняет критический раздел и затем отсылает сообщение обратно в почтовый ящик. Листинг 8.7. Реализация взаимных исключений с использованием сообщений
const int n = /* Количество процессов */;
void P(int n) {
message msg;
while(true) {
receive(mutex, msg);
/* Критический раздел */;
send(mutex, msg);
/* Остальной код */;
}
}
void main() {
create_mailbox(mutex);
send(mutex, null);
parbrgin(P(1),P(2),…,p(n));
}
Листинг 8.8. Решение задачи производитель-потребитель с ограниченным буфером с использованием сообщений
const int capacity = /* Емкость буфера */;
Null = /* Пустое сообщение */;
int I;
void producer() {
message pmsg;
while(true) {
receive(myproduce, pmsg);
pmsg = produce();
send(mayconsume, pmsg);
}
}
void consumer() {
message cmsg;
while(true) {
receive(myconsume, cmsg);
consume(cmsg);
send(mayproduce, null);
}
}
void main() {
create_mailbox(mayproduce);
create_mailbox(mayconsume);
for (int I = 1; I <= capacity; I++) send(mayproduce, null);
parbegin(producer, consumer);
}
В рассмотренном решении предполагается, что если операция receive выполняется параллельно более чем одним процессом, то:
если имеется сообщение, оно передается только одному из процессов, а остальные процессы блокируются;
если очередь сообщений пуста, блокируются все процессы; при появлении в очереди сообщения, его получает только один из заблокированных процессов.
Это предположение выполняется практически для всех средств передачи сообщений.
В качестве другого примера использования сообщений в листинге 8.8 приведено решение задачи производитель-потребитель с ограниченным буфером. В отличие от семафоров здесь передаются сообщения, а не сигналы. В программе используются два почтовых ящика. Когда производитель генерирует данные, он посылает их в качестве сообщения в почтовый ящик mayconsume. Пока в этом почтовом ящике имеется хотя бы одно сообщение, потребитель может получит данные. Следовательно, почтовый ящик mayconsume служит буфером, данные в котором организованы в виде очереди сообщений. “Емкость” этого буфера определяется глобальной переменной capacity. Почтовый ящик mayproduce изначально заполнен пустыми сообщениями в количестве, равном емкости буфера. Количество сообщений в этом почтовом ящике уменьшается при каждом поступлении новых данных и увеличивается при их использовании.
Такой подход достаточно гибкий – он может работать с любым количеством производителей и потребителей. Боле того, система производителей и потребителей может быть распределенной, когда все производители и почтовый ящик mayproduce находятся на одной машине, а потребители и почтовый ящик mayconsume – на другой.