ПАРАЛЛЕЛЬНОЕ ПРОГРАММИРОВАНИЕ
          
        
        
          
            28
          
        
        
          Введем два семафора:
        
        
          
            e
          
        
        
          - число пустых буферов и
        
        
          
            f
          
        
        
          - число заполненных бу-
        
        
          феров. Предположим, что запись в буфер и считывание из них являются критиче-
        
        
          скими секциями (как в примере с принт-сервером). Введем также двоичный семафор
        
        
          
            b
          
        
        
          , используемый для обеспечения взаимного исключения. Тогда процессы могут
        
        
          быть описаны следующим образом:
        
        
          // Глобальные переменные
        
        
          #define N 256
        
        
          int e = N, f = 0, b = 1;
        
        
          void Writer ()
        
        
          {
        
        
          while(1)
        
        
          {
        
        
          repareNextRecord(); /* подготовка новой записи */
        
        
          P(e); /* Уменьшить число свободных буферов, если они есть */
        
        
          /* в противном случае - ждать, пока они освободятся */
        
        
          P(b); /* Вход в критическую секцию */
        
        
          AddToBuffer(); /* Добавить новую запись в буфер */
        
        
          V(b); /* Выход из критической секции */
        
        
          V(f); /* Увеличить число занятых буферов */
        
        
          }
        
        
          void Reader ()
        
        
          {
        
        
          while(1)
        
        
          {
        
        
          P(f); /* Уменьшить число занятых буферов, если они есть */
        
        
          /* в противном случае ждать, пока они появятся */
        
        
          P(b); /* Вход в критическую секцию */
        
        
          GetFromBuffer(); /* Взять запись из буфера */
        
        
          V(b); /* Выход из критической секции */
        
        
          V(e); /* Увеличить число свободных буферов */
        
        
          ProcessRecord(); /* Обработать запись */
        
        
          }
        
        
          Достоинства:
        
        
          •
        
        
          пассивное ожидание (постановка в очередь и автоматическая выдача ресур-
        
        
          сов);
        
        
          •
        
        
          возможность управления группой однородных ресурсов.
        
        
          Недостаток: неправильное либо умышленное использование операций на
        
        
          семафоре допускает нарушение работоспособности параллельных систем.
        
        
          Действительно, если в рассмотренном примере переставить местами операции
        
        
          
            P(e)
          
        
        
          и
        
        
          
            P(b)
          
        
        
          в программе "писателе", то при некотором стечении обстоятельств эти
        
        
          два процесса могут взаимно заблокировать друг друга. Так, пусть "писатель" пер-
        
        
          вым войдет в критическую секцию и обнаружит отсутствие свободных буферов;