Выполняемая операция. Может быть отрицательным или положительным числом. Если число отрицательно, значение семафора будет уменьшено, а если положительным — увеличено. Не забывайте, освобождая ресурс, увеличивать значение семафора — за вас никто это не сделает. Если sem_op = 0, то процесс «заснет» и не «проснется» до тех пор, пока значение семафора не станет 0.
♦ sem_flg
Флаги операции, например, IPC_NOWAIT. Если IPC_NOWAIT не установлен, то процесс «заснет» до тех пор, пока не освободится указанное количество ресурсов (пока другой процесс не освободит их).
Чтобы лучше понять, что такое semop(), вернемся к нашим принтерам. Пусть у нас есть всего один принтер, умеющий выполнять только одно задание за раз. Начальное значение семафора принтера будет равно 1.
Перед посылкой задания на принтер нужно убедиться, что он свободен, то есть получить от семафора значение 1. Заполним массив sembuf необходимой для выполнения операции информацией:
struct sembuf prn_lock = {0, -1, IPC_NOWAIT};
Здесь 0 — это номер семафора: у нас всего один принтер, а нумерация начинается с нуля. -1 — это операция, запрашивающая единицу ресурса. Если принтер свободен, то после выполнения этой операции значение семафора принтера будет равно 0.
Мы также установили флаг IPC_NOWAIT, чтобы вызов прошел немедленно. Если принтер занят, вызов вернет ошибку:
if (semop(sid, &prn_lock, 1) == -1)
printf("Принтер занят\n");
Первый аргумент — это идентификатор объекта IPC, второй — это массив операций. Последний аргумент semop() говорит о том, что у нас есть только одна структура типа sembuf, то есть нам нужно выполнить только одну операцию.
После выполнения задания мы должны сообщить семафору об освобождении ресурса:
struct sembuf prn_unlock ={0, 1, IPC_NOWAIT};
semop(sid, &prn_unlock, 1);
В случае успеха, когда выполнены все операции, системный вызов semop() возвращает 0. В случае ошибки возвращается -1, а errno равна:
♦ E2BIG — количество операций (аргумент nsops) превышает разрешенное число операций;
♦ EACCESS — не хватает полномочий;
♦ EAGAIN — операция не может быть выполнена (при использовании флага IPC_NOWAIT), такую операцию нужно повторить снова;
♦ EFAULT — указатель sops указывает на ошибочный адрес;
♦ EIDRM — множество помечено на удаление;
♦ EINTR — прервано сигналом;
♦ EINVAL — неверный semid;
♦ ENOMEM — не хватает памяти для создания структуры Undo-операции;
♦ ERANGE — значение семафора вышло за пределы допустимых значений.
26.6.3. Контроль семафора
Для контроля семафора используется системный вызов semctl():
int semctl(int semid, int semnum, int cmd, union semun arg);
Первый аргумент — это идентификатор семафора, второй — номер семафора во множестве семафоров (нумерация начиняется с 0). В отличие от очереди сообщений, где достаточно было указать только идентификатор очереди, при работе с семафорами нужно обязательно указывать номер конкретного семафора, над которым вы хотите выполнить операцию. Третий аргумент — это команда, которую нужно выполнить над семафором. Возможные команды представлены в таблице 26.1.
Команды управления семафорами Таблица 26.1
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии