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

В листинге 2.6 показано, как с помощью семафоров решается проблема утраченных активизаций. Чтобы заставить их корректно работать, очень важно, чтобы их реализация предусматривала неделимый режим работы.
Вполне естественно было бы реализовать операции up и down в виде системных вызовов, чтобы операционная система на время тестирования семафора, обновления его значения и приостановки процесса при необходимости кратковременно запрещала все прерывания. Поскольку все эти действия занимают только несколько команд, запрет на прерывания не причинит никакого вреда. Если используются несколько центральных процессоров, каждый семафор должен быть защищен переменной lock, а для гарантии того, что семафор в отдельно взятый момент времени задействуется только одним центральным процессором, используется команда TSL или XCHG.

Нужно усвоить, что использование TSL или XCHG для предупреждения одновременного доступа к семафору нескольких центральных процессоров в корне отличается от режима активного ожидания производителем или потребителем момента опустошения или наполнения буфера. Операция работы с семафором займет лишь несколько микросекунд, а ожидание производителя или потребителя может быть сколь угодно долгим.

В этом решении используются три семафора: один из них называется full и предназначен для подсчета количества заполненных мест в буфере, другой называется empty и предназначен для подсчета количества пустых мест в буфере, третий называется mutex, он предотвращает одновременный доступ к буферу производителя и потребителя. Семафор full изначально равен 0, семафор empty изначально равен количеству мест в буфере, семафор mutex изначально равен 1. Семафоры, инициализированные значением 1 и используемые двумя или более процессами для исключения их одновременного нахождения в своих критических областях, называются двоичными семафорами. Взаимное исключение гарантируется в том случае, если каждый процесс совершает операцию down непосредственно перед входом в свою критическую область и операцию up сразу же после выхода из нее.

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

Затем при поступлении прерывания его обработчик выполняет операцию up в отношении связанного с устройством семафора, которая переводит соответствующий процесс в состояние готовности к продолжению выполнения. В этой модели шаг 5 из табл. 2.2 состоит из выполнения операции up над семафором устройства, с тем чтобы на шаге 6 планировщик мог запустить программу, управляющую устройством. Разумеется, если к этому моменту будут готовы
к выполнению сразу несколько процессов, планировщик может выбрать следующим для выполнения более важный процесс. Позже в этой главе мы еще рассмотрим некоторые алгоритмы, используемые для работы планировщика.

В примере, приведенном в листинге 2.6, семафоры используются двумя различными способами. Различия этих способов настолько важны, что требуют дополнительного разъяснения. Семафор mutex используется для организации взаимного исключения. Его предназначение — гарантировать, что в каждый отдельно взятый момент времени к буферу и соответствующим переменным имеет доступ по чтению или записи только один процесс. Организуемое взаимное исключение призвано предотвратить хаос. В следующем разделе мы изучим взаимное исключение и способы его достижения.

Листинг 2.6. Задача производителя и потребителя, решаемая с помощью семафоров #define N 100 typedef int semaphore;

semaphore mutex = 1; semaphore empty = N; semaphore full = 0; void producer(void)

{

int item; while (TRUE) { item = produce_item( );

down(&empty); down(&mutex); insert_item(item); up(&mutex); up(&full);

}

}

void consumer(void)

{

int item;

while (TRUE) { down(&full); down(&mutex); item = remove_item( ); up(&mutex); up(&empty); consume_item(item);

}

}

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

2.3.5.

<< | >>
Источник: Э. ТАНЕНБАУМ Х. БОС. СОВРЕМЕННЫЕ ОПЕРАЦИОННЫЕ СИСТЕМ Ы 4-е ИЗДАНИЕ. 2015

Еще по теме Решение задачи производителя-потребителя с помощью семафоров:

  1. 7. Каждый школьник – это сложнейший мир проблем и задач. Забота о своевременном решении этих проблем и задач составляет основу строительства новой школы
  2. ЗАДАЧА: РЕШЕНИЕ
  3. § 3. СТРУКТУРА РЕШЕНИЯ ПЕДАГОГИЧЕСКИХ ЗАДАЧ
  4. Психологические особенности решения задач.
  5. § 3. Мышление, интуиция, воображение в решении задач
  6. Правило подчинения общения решению задач правового воспитания.
  7. ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ ПО РЕШЕНИЮ ПСИХОЛОГО-ПЕДАГОГИЧЕСКИХ ЗАДАЧ
  8. Прием достижения момента истины в решении задач разговора.
  9. юридико-психологические исследования решения разных правоохранительных задач
  10. § 1. ПОНЯТИЕ О ПЕДАГОГИЧЕСКОЙ ДЕЯТЕЛЬНОСТИ КАК ПРОЦЕССЕ НЕПРЕРЫВНОГО РЕШЕНИЯ ПРОФЕССИОНАЛЬНЫХ ЗАДАЧ