11.3. Функция semop

11.3. Функция semop

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

#include <sys/sem.h>

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

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

Указатель opsptr указывает на массив структур вида

struct sembuf {

 short sem_num; /* номер семафора: 0, 1,… nsems-1 */

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

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

};

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

ПРИМЕЧАНИЕ

В структуре гарантированно содержатся только три указанных выше поля. Однако в ней могут быть и другие поля, причем порядок их может быть совершенно произвольным. Поэтому не следует статически инициализировать эту структуру кодом наподобие

struct sembuf ops[2] = {

 0, 0, 0, /* ждем, пока первый элемент не станет равен нулю */

 0, 1, SEM_UNDO /* затем увеличиваем [0] на 1 */

};

Вместо этого следует инициализировать ее динамически, как в нижеследующем примере:

struct sembuf ops[2];

ops[0].sem_num = 0; /* ждем, пока первый элемент не станет равен нулю */

ops[0].sem_op = 0;

ops[0].sem_flg = 0;

ops[1].sem_num = 0; /* затем увеличиваем [0] на 1 */

ops[1].sem_op = 1;

ops[1].sem_flg = SEM_UNDO;

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

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

? semval — текущее значение семафора (рис. 11.1);

? semncnt — количество потоков, ожидающих, пока значение семафора не станет больше текущего (рис. 11.1);

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

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

? когда выполнение потока приостанавливается до завершения операции с семафором (мы увидим, что поток может ожидать либо обнуления семафора, либо получения семафором положительного значения), поток перехватывает сигнал и происходит возвращение из обработчика сигнала, функция semop возвращает ошибку EINTR. Используя терминологию, введенную в книге [24, с. 124], можно сказать, что функция semop представляет собой медленный системный вызов, который прерывается перехватываемыми сигналами;

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

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

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

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

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

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

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

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

ПРИМЕЧАНИЕ

Если сравнить этот набор операций с теми, которые разрешены для семафоров Posix, мы увидим, что для последних определены только команды –1 (sem_wait) и +1 (sem_post). Для семафоров System V значение семафора может изменяться с шагом, отличным от 1, и кроме того, поток может ожидать, чтобы значение семафора стало нулевым. Эти операции являются более общими, что вместе с возможностью включения нескольких семафоров в набор делает семафоры System V более сложными, чем одиночные семафоры Posix.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Функция SUM

Из книги Обработка баз данных на Visual Basic®.NET автора Мак-Манус Джеффри П

Функция SUM Ваши возможности в подведении итогов не ограничены простым подсчетом записей. Используя функцию SUM, можно генерировать итоговые результаты для всех возвращаемых записей по любым числовым полям. Например, для создания запроса, который генерирует итоги по


Функция uni()

Из книги Fiction Book Designer Краткое руководство автора Автор неизвестен

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция uni()

Из книги Fiction Book Designer 3.2. Краткое руководство автора Izekbis

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Функция pthread_rwlock_init

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

Функция pthread_rwlock_init Первая функция, pthread_rwlock_init, динамически инициализирует блокировку чтения-записи. Ее текст приведен в листинге 8.2.7-8 Присваивание атрибутов с помощью этой функции не поддерживается, поэтому мы проверяем, чтобы указатель attr был нулевым.9-19 Мы


Функция pthread_rwlock_trywrlock

Из книги Технология XSLT автора Валиков Алексей Николаевич

Функция pthread_rwlock_trywrlock Неблокируемая функция pthread_rwlock_trywrlock показана в листинге 8.7.11-14 Если значение счетчика rw_refcount отлично от нуля, блокировка в данный момент уже установлена считывающим или записывающим процессом (это безразлично) и мы возвращаем ошибку с кодом EBUSY. В


Функция pthread_rwlock_unlock

Из книги PGP: Кодирование и шифрование информации с открытым ключом. автора Левин Максим

Функция pthread_rwlock_unlock Последняя функция, pthread_rwlock_unlock, приведена в листинге 8.8.Листинг 8.8. Функция pthread_rwlock_unlock: разблокирование ресурса//my_rwlock/pthread_rwlock_unlock.c1  #include "unpipc.h"2  #include "pthread_rwlock.h"3  int4  pthread_rwlock_unlock(pthread_rwlock_t *rw)5  {6   int result;7   if (rw->rw_magic != RW_MAGIC)8    return(EINVAL);9   if ((result =


Функция sem_open

Из книги Fiction Book Designer 3.2. Руководство по созданию книг автора

Функция sem_open В листинге 10.22 приведен текст функции sem_open, которая создает новый семафор или открывает существующий.Листинг 10.22. Функция sem_open//my_pxsem_fifo/sem_open.с1  #include "unpipc.h"2  #include "semaphore.h"3  #include <stdarg.h> /* для произвольного списка аргументов */4  mysem_t *5  mysem_open(const char *pathname, int


Функция sem_close

Из книги Введение в криптографию автора Циммерманн Филипп

Функция sem_close Текст функции sem_close приведен в листинге 10.23.11-15 Мы закрываем оба дескриптора и освобождаем память, выделенную под тип sem_t.Листинг 10.23. Функция sem_close//my_pxsem_fifo/sem_close.с1  #include "unpipc.h"2  #include "semaphore.h"3  int4  mysem_close(mysem_t *sem)5  {6   if (sem->sem_magic != SEM_MAGIC) {7    errno =


Хэш-функция.

Из книги автора

Хэш-функция. Еще одно важное преимущество использования PGP состоит в том, что PGP применяет так называемую «хэш-функцию», которая действует таким образом, что в том случае какого-либо изменения информации, пусть даже на один бит, результат «хэш-функции» будет совершенно


Функция uni()

Из книги автора

Функция uni() Поиск/замена символа по его юникодному номеру также может быть сделана при помощи функции uni().Пример функции uni(): Boouni(107,32)Designer найдет слово Book


Хэш-функция

Из книги автора

Хэш-функция Однако описанная выше схема имеет ряд существенных недостатков. Она крайне медлительна и производит слишком большой объём данных — по меньшей мере вдвое больше объёма исходной информации. Улучшением такой схемы становится введение в процесс преобразования