GETPID Эта команда получает идентификатор процесса, который совершал последнюю операцию над семафором с индексом semnum.
GETNCNT Эта команда получает количество процессов, ожидающих увеличения значения семафора по сравнению с текущим.
GETZCNT Эта команда получает количество процессов, ожидающих, пока значение семафора не станет 0.
IPC_RMID Эта команда удаляет набор семафоров и его идентификатор. Если какие-то процессы были заблокированы в операциях с этим набором, во всех этих процессах соответствующие вызовы semop(2) вернут ошибку EIDRM.
semctl(2) - ПРИМЕРЫ. описания и системный вызов для создания набора семафоров
#include <sys/types. h>
#include <sys/ipc. h>
#include <sys/sem. h>
#define ANY 0
int semid, rtn;
struct semid_ds ds;
ushort us[5], init_us[5] = { 0, 6, 7, 1, 4 };
...
semid = semget(key, 5, IPC_CREAT | 0660);
. инициализировать один семафор из набора
semctl(semid, 2, SETVAL, 7);
. получить значение одного семафора из набора
/* такой же формат для GETNCNT, GETZCNT, GETPID */
rtn = semctl (semid, 2, GETVAL, ANY);
. инициализировать все семафоры в наборе
semctl (semid, ANY, SETALL, init_us);
. получить все значения семафоров в наборе
semctl (semid, ANY, GETALL, us);
. изменить хозяина
/* также изменяются права доступа */
semctl (semid, ANY, IPC_STAT, &ds);
ds. sem_perm. uid = 51; /* new uid */
semctl (semid, ANY, IPC_SET, &ds);
. удалить набор семафоров
semctl (semid, ANY, IPC_RMID, ANY);
Инициализировать и удалить семафор - Пример
Это тот же пример, что и выше, но здесь показан код для инициализации семафора и его удаления. Этот фрагмент программы работает так:
32-37 Если эта программа создала набор семафоров, инициализировать его в 1. Как правило, набор семафоров должен быть удален перед выходом из программы, если его инициализация не удалась, но это здесь не показано.
54-60 Cоздатель набора семафоров может удалить его. В нашей программе, по соглашению, удалением семафоров занимается тот же процесс, который их создал. Обратите внимание на использование "пустых" аргументов в тех местах, где соответствующие параметры системных вызовов не используются. Функция sleep(3C) задерживает удаление семафора на 5 секунд, так что другая программа может продолжать работу с ним.
Файл: semdemo. c
ИНИЦИАЛИЗИРОВАТЬ И УДАЛИТЬ СЕМАФОР - ПРИМЕР
1 #include <unistd. h>
2 #include <stdlib. h>
3 #include <sys/types. h>
4 #include <sys/ipc. h>
5 #include <sys/sem. h>
6 #include <stdio. h>
7 #define DUMMY 0
8 #define COUNT 4
9
10 main(int argc, char *argv[])
11 {
...
32 if (creator) {/* initialize semaphore */
33 if (semctl(semid, 0, SETVAL, 1) == -1) {
34 perror(argv[0]);
35 exit(2);
36 }
37 }
...
54 if (creator) {
55 sleep(5);
56 if(semctl(semid, DUMMY, IPC_RMID, DUMMY) == -1) {
57 perror(argv[0]);
58 exit(5);
59 }
60 }
61 return(0);
62 }
Операции над семафорами
Системный вызов semop(2) производит операции над одним или более семафорами из набора. Операции увеличивают или уменьшают значение семафора на заданную величину, или ожидают, пока семафор не станет нулевым.
Аргументы этого системного вызова таковы:
semid Идентификатор набора семафоров.
sops Адрес массива с элементами типа struct sembuf. Каждый элемент задает одну операцию над одним семафором. По этому адресу должно размещаться nsops таких структур. Эта структура определена следующимобразом:
sys/sem. h:
struct sembuf {
ushort sem_num; /* semaphore */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
Поля этой структуры имеют следующий смысл:
sem_num Индекс семафора, над которым производится операция.
sem_op Если это значение положительно, оно добавляется к текущему значению семафора (POST).
Если sem_op отрицательно, и его абсолютное значение больше текущего значения семафора, операция обычно блокируется. Иначе, из семафора просто вычитается абсолютное значение этого поля (WAIT).
Если sem_op равен нулю, операция блокируется, пока семафор не станет нулевым.
sem_flg Это поле задает дополнительные флаги. Нулевое значение означает, что не задано никаких флагов. Допустимы следующие флаги, объединяемые побитовым ИЛИ:
IPC_NOWAIT Если установлен этот флаг, и операция должна была бы привести к блокировке, semop(2) возвращает неуспех. Этот флаг может быть использован для анализа и изменения значения семафора без блокировки.
SEM_UNDO Если этот флаг установлен, при завершении процесса (как по exit(2), так и по сигналу), операция будет отменена. Это защищает от посмертной блокировки ресурса процессом, который ненормально завершился, не успев освободить ресурс.
Использование SEM_UNDO отменяет операцию над семафором, но не обеспечивает, что ресурс, защищаемый этим семафором, остался в согласованном состоянии после завершения процесса.
Кроме того, нужно иметь в виду, что отмена операций реализована в виде счетчика, в котором накапливаются все значения, добавляемые и вычитаемые процессом при операциях над данным семафором. При завершении процесса этот счетчик просто вычитается из текущего значения семафора. Из этого описания должно быть ясно, что если вы используете флаг SEM_UNDO, его необходимо использовать при всех операциях над этим семафором. Если вы указываете SEM_UNDO только при операциях LOCK, но не при UNLOCK, счетчик отмены может просто переполниться, а его применение к семафору может привести к нежелательным результатам.
При выполнении операции над несколькими семафорами, значения семафоров не меняются, пока не окажется, что все требуемые операции могут быть успешно выполнены. При этом, поведение системы в случае, когда набор операций содержит несколько разных операций над одним и тем же семафором, не стандартизовано. Разные реализации POSIX могут интерпретировать такой набор по разному.
nsops Количество структур в массиве, на который указывает sops. nsops должен всегда быть больше или равен 1. Параметр prctl(1) process. max-sem-ops ограничивает максимальное количество операций в одном наборе.
Блокировка ресурса - Пример
Здесь показан фрагмент программы для захвата и освобождения ресурса. Разделяемым ресурсом является возможность вывода на терминал. Обычно, если два процесса одновременно пишут на терминал, то вывод обоих процессов смешивается на экране.
В этом примере программа использует семафоры, чтобы получить исключительный доступ к терминалу и напечатать текстовую строку. Если эта программа параллельно исполняется двумя процессами, то процессы будут использовать терминал по очереди.
Этот фрагмент программы работает следующим образом:
14-17 Эти командные структуры задают операцию захвата (вычесть 1) и операцию освобождения (добавить один). Флаг SEM_UNDO используется для восстановления предыдущего значения семафора, если программа, изменившая его, ненормально завершится. Один из способов вызвать ненормальное завершение программы - нажать клавишу BREAK или DEL на терминале.
... Отсутствующий код содержит вызов semget(2) для создания набора из одного семафора и semctl(2) для установки его значения в 1 командой SETVAL.
41-44 Здесь семафор уменьшается на 1, блокируя (захватывая) ресурс.
45 Печатается сообщение о том, что ресурс заблокирован. Заметьте, что вывод не завершается переводом каретки, то есть это будет еще не вся строка вывода. В пропущенном коде необходимо выключить буферизацию stdio, чтобы неполные строки выводились на устройство.
46 sleep(3C) изображает использование терминала. Кроме того, это освобождает процессор на время, пока процесс спит.
47-51 Печатается сообщение, что ресурс освобождается. Затем ресурс действительно освобождается увеличением значения семафора на 1.
Ниже приведена выдача двух экземпляров этой программы, запущенных в
фоновом режиме. Это может быть сделано одной командной строкой.
$ semdemo & semdemo &
12423
12424
$ [12423] locking[12423] unlocking
[12424] locking[12424] unlocking
[12423] locking[12423] unlocking
[12424] locking[12424] unlocking
[12423] locking[12423] unlocking
[12424] locking[12424] unlocking
[12423] locking[12423] unlocking
[12424] locking[12424] unlocking
Заметьте, что каждый процесс по очереди пишет полную строку на стандартный вывод, являющийся сейчас разделяемым ресурсом.
Файл: semdemo. c
БЛОКИРОВКА РЕСУРСА - ПРИМЕР
1 #include <unistd. h>
2 #include <stdlib. h>
3 #include <sys/types. h>
4 #include <sys/ipc. h>
5 #include <sys/sem. h>
6 #include <stdio. h>
7 #define DUMMY 0
8 #define COUNT 4
9
10 main(int argc, char *argv[])
11 {
...
14 static struct sembuf lock =
15 { 0, -1, SEM_UNDO };
16 static struct sembuf unlock =
17 { 0, 1, SEM_UNDO };
...
39 pid = getpid();
40 for (i = 0; i < COUNT; i++ ) {
41 if (semop(semid, &lock, 1) == -1) {
42 perror(argv[0]);
43 exit(3);
44 }
45 printf("[%d] locking\t", pid);
46 sleep(1);/* terminal output being used */
47 printf("[%d] unlocking\n", pid);
48 if (semop(semid, &unlock, 1) == -1) {
49 perror(argv[0]);
50 exit(4);
51 }
52 }
...
62 }
Набор семафоров - Использование
Этот пример иллюстрирует использование набора семафоров, содержащего более чем один семафор. Этот набор используется для управления ресурсами печати. Существует три отдельных ресурса, и каждому из них соответствует собственный семафор в наборе. Эти ресурсы суть все принтеры вместе, механический принтер и лазерный принтер. Заметьте, что семафор 0, первый в наборе, инициализирован значением 2, т. к. в общем принтерном ресурсе есть два принтера. Пунктирные линии показывают связи между тремя ресурсами и тремя семафорами.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 |


