Читаем Архитектура операционной системы UNIX (ЛП) полностью

реализующих операцию блокирования более дешевыми средствами, ибо циклы, входящие в функцию Pprim, работают медленно и снижают производительность системы. Так, например, в машинах серии IBM 370 поддерживается инструкция compare and swap (сравнить и переставить), в машине AT amp;T 3B20 — инструкция read and clear (прочитать и очистить). При выполнении инструкции read and clear процессор считывает содержимое ячейки памяти, очищает ее (сбрасывает в 0) и по результатам сравнения первоначального содержимого с 0 устанавливает код завершения инструкции. Если ту же инструкцию над той же ячейкой параллельно выполняет еще один процессор, один из двух процессоров прочитает первоначальное содержимое, а другой — 0: неделимость операции гарантируется аппаратным путем. Таким образом, за счет использования данной инструкции функцию Pprim можно было бы реализовать менее сложными средствами (Рисунок 12.7). Процесс повторяет инструкцию read and clear в цикле до тех пор, пока не будет считано значение, отличное от нуля. Начальное значение компоненты семафора, связанной с блокировкой, должно быть равно 1.

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

struct semaphore {

 int val[NUMPROCS]; /* замок 1 элемент на каждый процессор */

 int lastid; /* идентификатор процессора, получившего семафор последним */

};

int procid; /* уникальный идентификатор процессора */

int lastid; /* идентификатор процессора, получившего семафор последним */

INIT(semaphore)

struct semaphore semaphore;

{

 int i;

 for (i = 0; i ‹ NUMPROCS; i++) semaphore.val[i] = 0;

}

Pprim(semaphore)

struct semaphore semaphore;

{

 int i, first;

loop:

 first = lastid;

 semaphore.val[procid] = 1;

forloop:

 for (i = first; i ‹ NUMPROCS; i++) {

  if (i == procid) {

   semaphore.val[i] = 2;

   for (i = 1; i ‹ NUMPROCS; i++) if (i != procid && semaphore.val[i] == 2) goto loop;

   lastid = procid;

   return; /* успешное завершение, ресурс можно использовать */

  }

  else if (semaphore.val[i]) goto loop;

 }

 first = 1;

 goto forloop;

}

Vprim(semaphore)

struct semaphore semaphore;

{

 lastid = (procid + 1) % NUMPROCS;

 /* на следующий процессор */

 semaphore.val[procid] = 0;

}

Рисунок 12.6. Реализация семафорной блокировки на Си

Перейти на страницу:

Похожие книги