5.2.3. Операции ожидания и установки
5.2.3. Операции ожидания и установки
Каждый семафор имеет неотрицательное значение и поддерживает операции ожидания и установки. Системный вызов semop() реализует обе операции. Первым аргументом функции является идентификатор группы семафоров. Второй аргумент — это массив значений типа struct sembuf, задающих выполняемые операции. Третий аргумент — это длина массива.
Ниже перечислены поля структуры sembuf.
? sem_num — номер семафора в группе.
? sem_op — число, задающее операцию.
Если данное поле содержит положительное число, оно немедленно добавляется к значению семафора.
Если данное поле содержит отрицательное число, то модуль числа вычитается из значения семафора. Операции, приводящие к установке отрицательного значения, блокируются до тех пор, пока значение семафора не станет достаточно большим (вследствие действий других процессов).
Если данное поле равно нулю, операция блокируется до тех пор, пока значение семафора не станет равным нулю.
? sem_flg — это значение флага. Флаг IPC_NOWAIT предотвращает блокирование операции. Если запрашиваемая операция приведет к блокированию, функция semop() завершится выдачей кода ошибки. При наличии флага SEM_UNDO ОС Linux автоматически отменит выполненную операцию по завершении процесса.
В листинге 5.4 иллюстрируются операции ожидания и установки двоичного семафора.
Листинг 5.4. (sem_pv.c) Ожидание и установка двоичного семафора
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
/* Ожидание семафора. Операция блокируется до тех пор, пока
значение семафора не станет положительным, после чего
значение уменьшается на единицу. */
int binary_semaphore_wait(int semid) {
struct sembuf operations[1];
/* Оперируем одним-единственным семафором. */
operations[0].sem_num = 0;
/* Уменьшаем его значение на единицу. */
operations[0].sem_op = -1;
/* Разрешаем отмену операции. */
operations[0].sem_flg = SEM_UNDO;
return semop(semid, operations, 1);
}
/* Установка семафора: его значение увеличивается на единицу.
Эта операция завершается немедленно. */
int binary_semaphore_post(int semid) {
struct sembuf operations[1];
/* оперируем одним-единственным семафором. */
operations[0].sem_num = 0;
/* Увеличиваем его значение на единицу. */
operations[0].sem_op = 1;
/* Разрешаем отмену операции. */
operations[0].sem_flg = SEM_UNDO;
return semop(semid, operations, 1);
}
Флаг SEM_UNDO позволяет решить проблему, возникающую при завершении процесса, которого есть ресурсы, связанные с семафором. Как бы ни завершился процесс — принудительно или естественным образом, — значение семафора автоматически корректируется. "отменяя" эффект операции, выполненной над семафором. Например, если процесс уменьшил значение семафора, а затем был уничтожен командой kill, значение семафора будет снова увеличено.