Книга: UNIX: взаимодействие процессов
11.1.Введение
11.1.Введение
В главе 10 мы описывали различные виды семафоров, начав с:
? бинарного семафора, который может принимать только два значения: 0 и 1. По своим свойствам такой семафор аналогичен взаимному исключению (глава 7), причем значение 0 для семафора соответствует блокированию ресурса, а 1 — освобождению.
Далее мы перешли к более сложному виду семафоров:
? семафор-счетчик, значение которого лежит в диапазоне от 0 до некоторого ограничения, которое, согласно Posix, не должно быть меньше 32767. Они использовался для подсчета доступных ресурсов в задаче о производителях и потребителях, причем значение семафора соответствовало количеству доступных ресурсов.
Для обоих типов семафоров операция wait состояла в ожидании изменения значения семафора с нулевого на ненулевое и последующем уменьшении этого значения на 1. Операция post увеличивала значение семафора на 1, оповещая об этом все процессы, ожидавшие изменения значения семафора.
Для семафоров System V определен еще один уровень сложности:
? набор семафоров-счетчиков — один или несколько семафоров, каждый из которых является счетчиком. На количество семафоров в наборе существует ограничение (обычно порядка 25 — раздел 11.7). Когда мы говорим о семафоре System V, мы подразумеваем именно набор семафоров-счетчиков, а когда говорим о семафоре Posix, подразумевается ровно один семафор-счетчик.
Для каждого набора семафоров ядро поддерживает следующую информационную структуру, определенную в файле <sys/sem.h>:
struct semid_ds {
struct ipc_perm sem_perm; /* разрешения на операции */
struct sem *sem_base; /*указатель на массив семафоров в наборе */
ushort sem_nsems; /* количество семафоров в наборе */
time_t sem_otime; /* время последнего вызова semop(); */
time_t sem_ctime; /* время создания последнего IPC_SET */
};
Структура ipc_perm была описана в разделе 3.3. Она содержит разрешения доступа для данного семафора.
Структура sem представляет собой внутреннюю структуру данных, используемую ядром для хранения набора значений семафора. Каждый элемент набора семафоров описывается так:
struct sem {
ushort_t semval; /* значение семафора, неотрицательно */
short sempid; /* PID последнего процесса, вызвавшего semop(), SETVAL, SETALL */
ushort_t semncnt; /* количество ожидающих того, что значение семафора превысит текущее */
ushort_t semzcnt; /* количество ожидающих того, что значение семафора станет равным 0*/
};
Обратите внимание, что sem_base представляет собой указатель на массив структур типа sem — по одному элементу массива на каждый семафор в наборе.
Помимо текущих значений всех семафоров набора в ядре хранятся еще три поля данных для каждого семафора: идентификатор процесса, изменившего значение семафора последним, количество процессов, ожидающих увеличения значения семафора, и количество процессов, ожидающих того, что значение семафора станет нулевым.
ПРИМЕЧАНИЕ
В стандарте Unix 98 данная структура не имеет имени. Приведенное выше имя (sem) взято из реализации System V.
Любой конкретный семафор в ядре мы можем воспринимать как структуру semid_ds, указывающую на массив структур sem. Если в наборе два элемента, мы получим картину, изображенную на рис. 11.1. На этом рисунке переменная sem_nsems имеет значение 2, а каждый из элементов набора идентифицируется индексом ([0] или [1]).
Рис. 11.1. Структуры данных ядра для набора семафоров из двух элементов