Linux: Полное руководство
Шрифт:
♦ sem_flg
Флаги операции, например, IPC_NOWAIT. Если IPC_NOWAIT не установлен, то процесс «заснет» до тех пор, пока не освободится указанное количество ресурсов (пока другой процесс не освободит их).
Чтобы лучше понять, что такое semop, вернемся к нашим принтерам. Пусть у нас есть всего один принтер, умеющий выполнять только одно задание за раз. Начальное значение семафора принтера будет равно 1.
Перед посылкой задания на принтер нужно убедиться, что он свободен, то есть получить от семафора значение 1. Заполним массив sembuf необходимой для выполнения операции информацией:
Здесь 0 — это номер семафора: у нас всего
– 1 — это операция, запрашивающая единицу ресурса. Если принтер свободен, то после выполнения этой операции значение семафора принтера будет равно 0.
Мы также установили флаг IPC_NOWAIT, чтобы вызов прошел немедленно. Если принтер занят, вызов вернет ошибку:
Первый аргумент — это идентификатор объекта IPC, второй — это массив операций. Последний аргумент semop говорит о том, что у нас есть только одна структура типа sembuf, то есть нам нужно выполнить только одну операцию.
После выполнения задания мы должны сообщить семафору об освобождении ресурса:
В случае успеха, когда выполнены все операции, системный вызов semop возвращает 0. В случае ошибки возвращается -1, а errno равна:
♦ E2BIG — количество операций (аргумент nsops) превышает разрешенное число операций;
♦ EACCESS — не хватает полномочий;
♦ EAGAIN — операция не может быть выполнена (при использовании флага IPC_NOWAIT), такую операцию нужно повторить снова;
♦ EFAULT — указатель sops указывает на ошибочный адрес;
♦ EIDRM — множество помечено на удаление;
♦ EINTR — прервано сигналом;
♦ EINVAL — неверный semid;
♦ ENOMEM — не хватает памяти для создания структуры Undo-операции;
♦ ERANGE — значение семафора вышло за пределы допустимых значений.
26.6.3. Контроль семафора
Для контроля семафора используется системный вызов semctl:
Первый аргумент — это идентификатор семафора, второй — номер семафора во множестве семафоров (нумерация начиняется с 0). В отличие от очереди сообщений, где достаточно было указать только идентификатор очереди, при работе с семафорами нужно обязательно указывать номер конкретного семафора, над которым вы хотите выполнить операцию. Третий аргумент — это команда, которую нужно выполнить над семафором. Возможные команды представлены в таблице 26.1.
Команды управления семафорами Таблица 26.1
Команда | Назначение |
---|---|
IPC_STAT | Запоминает структуру semid_ds для множества по адресу buf объединения semun (чуть позже мы подробно рассмотрим эту структуру и объединение semun) |
IPC_SET | Устанавливает значение члена ipc_perm структуры semid_ds |
IPC_RMID | Удаляет множество |
GETALL | Позволяет получить значения всех семафоров. Значения возвращаются в виде массива unsigned short, на который указывает член объединения array |
GETNCNT | Возвращает число процессов, которые ожидают ресурсы в данный момент |
GETPID | Возвращает PID процесса, выполнившего последний вызов semop |
GETVAL | Возвращает значение одного семафора |
GETZCNT | Возвращает число процессов, которые ожидают полного освобождения ресурса |
SETALL | Устанавливает значение семафоров. Значения берутся из члена array объединения semun |
SETVAL | Устанавливает значение конкретного семафора. Значение берется из элемента val объединения semun |
Последний аргумент — это объединение (union) аргументов, которые можно использовать для управления семафором. Рассмотрим подробнее это объединение, объявленное в файле
Первый член этого объединения val используется для установки значения одного семафора при использовании команды SETVAL.
Член buf используется командами IPC_STAT и IPC_SET. Это копия внутренней структуры данных семафора.
Указатель на массив array используется командами GETALL и SETALL для получения или установки значений всех семафоров во множестве.
Последние два члена объединения специфичны только для Linux — в других UNIX-системах вы их не найдете. Эти элементы использует ядро.
В случае успеха системный вызов semctl возвращает натуральное число, а в случае ошибки -1. Переменная errno равна:
♦ EACCESS — не хватает полномочий;
♦ EFAULT — адрес arg ошибочен;
♦ EIDRM — множество помечено для удаления:
♦ EINVAL — неправильный аргумент semid;
♦ EPERM — у вас нет прав для выполнения команды cmd;
♦ ERANGE — значение семафора вышло за пределы допустимых значений.
Пример получения значения семафора с номером N из множества sid:
Предположим, что нам нужно вывести состояние всех трех имеющихся принтеров:
А вот код инициализации всех семафоров множества semid:
Довольно часто возникают определенные сложности с установкой прав доступа к множеству семафоров. Рассмотрим следующий код, позволяющий установить права доступа к множеству semid. Права доступа задаются в виде строки, например, «0660».