Скачиваний:
90
Добавлен:
12.05.2015
Размер:
913.92 Кб
Скачать

19.3. Функция semop

После инициализации семафора вызовом semgetс одним или несколькими семафорами набора можно выполнять некоторые действия с помощью функцииsemop:

#include <sys/sem.h>

int semop (int semid, struct sembuf *opsptr, size_t nops);

/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */

Указатель opsptrуказывает на массив структур следующего вида:

struct sembuf

{

unsigned short sem_num; /* номер семафора: 0, 1, ..., sem_nsems-1 */

short sem_op; /* операция над семафором: <0, 0, >0 */

short sem_flg; /* флаги операции: 0, IPC_NOWAIT, SEM_UNDO */

};

Количество элементов в массиве структур sembuf, на который указываетopsptr, задается аргументомnops. Каждый элемент этого массива определяет операцию с одним конкретным семафором набора. Номер семафора указывается в полеsem_numи принимает значение 0 для первого семафора, 1 – для второго и т. д., доsem_nsems-1, гдеsem_nsemsсоответствует количеству семафоров в наборе (второй аргумент в вызовеsemgetпри создании семафора).

Весь массив операций, передаваемый функции semop, выполняется ядром как одна операция; атомарность при этом гарантируется. Ядро выполняет все указанные операции или ни одну из них.

Каждая операция задается значением sem_op, которое может быть отрицательным, нулевым или положительным. Сделаем несколько утверждений, которыми мы будем пользоваться при дальнейшем обсуждении:

  • semval– текущее значение семафора (рис. 18.2);

  • semncnt– количество потоков, ожидающих, пока значение семафора не увеличится (рис. 18.2);

  • semzcnt– количество потоков, ожидающих, пока значение семафора не станет нулевым (рис. 18.2);

  • semadj– корректировочное значение данного семафора для вызвавшего процесса. Это значение изменяется, только если при вызове функцииsemopв полеsem_flgструктурыsembufбыл указан флагSEM_UNDO. Эта переменная создается в ядре для каждого процесса в отдельности, который указал флагSEM_UNDO;

  • когда выполнение потока приостанавливается до завершения операции с семафором (мы увидим, что поток может ожидать либо обнуления семафора, либо получения семафором положительного значения), поток может перехватить сигнал. По возвращении из обработчика сигнала функция semopвозвращает ошибкуEINTR. Другими словами, функцияsemopпредставляет собой медленный системный вызов (раздел 10.5), который может быть прерван перехватываемыми сигналами;

  • когда выполнение потока приостанавливается до завершения операции с семафором и этот семафор удаляется из системы другим потоком или процессом, функция semopвозвращает ошибкуEIDRM.

Опишем теперь работу функции semopв зависимости от трех возможных значений, которые может принимать полеsem_opструктурыsembuf: положительного, нулевого и отрицательного.

  1. Если значение sem_opположительно, оно добавляется кsemval. Такое действие соответствует освобождению ресурсов, доступом к которым управляет семафор. Если указан флагSEM_UNDO, значениеsem_opвычитается из значенияsemadjданного семафора.

  2. Если значение sem_opравно нулю, вызвавший поток блокируется до тех пор, пока текущее значение семафора (semval) не станет нулевым. Еслиsemvalуже равно нулю, происходит немедленный возврат из функции.

Если значение semvalне равно нулю, то ядро увеличивает значение поляsemzcntданного семафора и вызвавший поток блокируется до тех пор, пока значениеsemvalне станет нулевым (после чего значениеsemzcntбудет уменьшено на единицу). Как отмечалось ранее, поток будет приостановлен, только если не указан флагIPC_NOWAIT. Если семафор будет удален в процессе ожидания или будет перехвачен сигнал, произойдет преждевременный возврат из функции и будет возвращен соответствующий код ошибки.

  1. Если значение sem_opотрицательно, вызвавший поток блокируется до тех пор, пока текущее значение семафора не станет большим или равным модулюsem_op. Это действие соответствует запросу ресурсов. Если значениеsemvalбольше или равно модулюsem_op, модульsem_opвычитается изsemval. Если указан флагSEM_UNDO, модульsem_opдобавляется к значениюsemadjданного семафора.

Если значение semvalменьше модуляsem_op, значение поляsemncntданного семафора увеличивается на единицу, а вызвавший поток блокируется до тех пор, пока значениеsemvalне станет большим или равным модулюsem_op. Когда это произойдет, поток будет разблокирован, значениеsemvalбудет уменьшено на модульsem_opи из значенияsemncntбудет вычтена единица. Если указан флагSEM_UNDO, модульsem_opдобавляется к значениюsemadjданного семафора. Как отмечалось ранее, поток не будет приостановлен, если указан флагIPC_NOWAIT. Ожидание завершается преждевременно, если будет перехвачен сигнал или семафор будет удален другим потоком.

Соседние файлы в папке Chapter.4