Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
26-30.docx
Скачиваний:
9
Добавлен:
08.09.2019
Размер:
118.7 Кб
Скачать

26

Решение задачи производителя/потребителя с использованием семафоров.

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

Producer:

while(1) {

produce_item;

put_item;

}

Consumer:

while(1) {

get_item;

consume_item;

}

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

Возьмем три семафора empty, full и mutex. Семафор full будем использовать для гарантии того, что потребитель будет ждать, пока в буфере появится информация. Семафор empty будем использовать для организации ожидания производителя при заполненном буфере, а семафор mutex - для организации взаимоисключения на критических участках, которыми являются действия put_item и get_item (операции положить информацию и взять информацию не могут пересекаться, так как тогда возникнет опасность искажения информации). Тогда решение задачи выглядит так:

Semaphore mutex = 1;

Semaphore empty = N, где N – емкость буфера;

Semaphore full = 0;

Producer:

while(1) {

produce_item;

P(empty);

P(mutex);

put_item;

V(mutex);

V(full);

}

Consumer:

while(1) {

P(full);

P(mutex);

put_item;

V(mutex);

V(empty);

consume_item;

}

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

27

Простейшие средства межпроцессного взаимодействия в Unix.

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

Семафоры

Одним из первых механизмов, предложенных для синхронизации поведения процессов, стали семафоры, концепцию которых описал Дейкстра (Dijkstra) в 1965 году.

Дейкстра предложил две операции, down и up. Операция down сравнивает значение семафора с нулем. Если значение семафора больше нуля, операция down уменьшает его и просто возвращает управление. Если значение семафора равно нулю, процедура down не возвращает управление процессу, а процесс переводится в состояние ожидания. Все операции проверки значения семафора, его изменения и перевода процесса в состояние ожидания выполняются как единое и неделимое элементарное действие. Тем самым гарантируется, что после начала операции ни один процесс не получит доступа к семафору до окончания или блокирования операции. Атомарность операции чрезвычайно важна для разрешения проблемы синхронизации и предотвращения состояния состязания.

Операция up увеличивает значение семафора. Если с этим семафором связаны один или несколько ожидающих процессов, которые не могут завершить более раннюю операцию down, один из них выбирается системой (например, случайным образом) и ему разрешается завершить свою операцию down. Таким образом, после операции up, примененной к семафору, связанному с несколькими ожидающими процессами, значение семафора так и останется равным 0, но число ожидающих процессов уменьшится на единицу. Операция увеличения значения семафора и активизации процесса тоже неделима. Ни один процесс не может быть блокирован во время выполнения операции up, как ни один процесс не мог быть блокирован во время выполнения операции wakeup в предыдущей модели.

POSIX — sem_init(), sem_wait(), sem_post(), sem_destroy().

Мьютекс — упрощенная версия семафора, которая может находиться в одном из двух состояний — блокированном или неблокированном.

POSIX — mutex_init(), mutex_lock(), mutex_unlock(), mutex_destroy().

Монитор — механизм организации параллелизма, который содержит как данные, так и процедуры, необходимые для обеспечения доступа к неразделяемым ресурсам.

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

Передача сообщений

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

Барьеры

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

28