Читаем Операционная система UNIX полностью

int semget(key_t key, int nsems, int semflag);

В случае успешного завершения операции функция возвращает дескриптор объекта, в случае неудачи - -1. Аргумент nsems задает число семафоров в группе. В случае, когда мы не создаем, а лишь получаем доступ к существующему семафору, этот аргумент игнорируется. Аргумент semflag определяет права доступа к семафору и флажки для его создания (IPC_CREAT, IPC_EXCL).

После получения дескриптора объекта процесс может производить операции над семафором, подобно тому, как после получения файлового дескриптора процесс может читать и записывать данные в файл. Для этого используется системный вызов semop(2):

#include

#include

#include

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

В качестве второго аргумента функции передается указатель на структуру данных, определяющую операции, которые требуется произвести над семафором с дескриптором semid. Операций может быть несколько, и их число указывается в последнем аргументе nops. Важно, что ядро обеспечивает атомарность выполнения критических участков операций (например, проверка значения — изменение значения) по отношению к другим процессам.

Каждый элемент набора операций semop имеет вид:

struct sembuf {

 short sem_num; /* номер семафора в группе */

 short sem_op;  /* операция */

 short sem_flg; /* флаги операции */

}

UNIX допускает три возможные операции над семафором, определяемые полем semop:

1. Если величина semop положительна, то текущее значение семафора увеличивается на эту величину.

2. Если значение semop равно нулю, процесс ожидает, пока семафор не обнулится.

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

Можно заметить, что первая операция изменяет значение семафора (безусловное выполнение), вторая операция только проверяет его значение (условное выполнение), а третья — проверяет, а затем изменяет значение семафора (условное выполнение).

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

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

В качестве примера рассмотрим два случая использования бинарного семафора (т.е. значения которого могут принимать только 0 и 1). В первом примере значение 0 является разрешающим, а 1 запирает некоторый разделяемый ресурс (файл, разделяемая память и т.п.), ассоциированный с семафором. Определим операции, запирающие ресурс и освобождающие его:

static struct sembuf sop_lock[2] = {

 0, 0, 0, /* ожидать обнуления семафора */

 0, 1, 0  /* затем увеличить значение семафора на 1 */

};

static struct sembuf sop_unlock[1] = {

 0,-1, 0 /* обнулить значение семафора */

};

Итак, для запирания ресурса процесс производит вызов:

semop(semid, &sop_lock[0], 2);

обеспечивающий атомарное выполнение двух операций:[43]

1. Ожидание доступности ресурса. В случае, если ресурс уже занят (значение семафора равно 1), выполнение процесса будет приостановлено до освобождения ресурса (значение семафора равно 0).

2. Запирание ресурса. Значение семафора устанавливается равным 1. Для освобождения ресурса процесс должен произвести вызов:

semop(semid, &sop_unlock[0], 1);

который уменьшит текущее значение семафора (равное 1) на 1, и оно станет равным 0, что соответствует освобождению ресурса. Если какой-либо из процессов ожидает ресурса (т. е. произвел вызов операции sop_lock), он будет "разбужен" системой, и сможет в свою очередь запереть ресурс и работать с ним.

Во втором примере изменим трактовку значений семафора: значению 1 семафора соответствует доступность некоторого ассоциированного с семафором ресурса, а нулевому значению — его недоступность. В этом случае содержание операций несколько изменится.

static struct sembuf sop_lock[2] = {

 0, -1, 0, /* ожидать разрешающего сигнала (1),

              затем обнулить семафор */

};

static struct sembuf sop_unlock[1] = {

Перейти на страницу:

Похожие книги

Архитектура операционной системы UNIX (ЛП)
Архитектура операционной системы UNIX (ЛП)

Настоящая книга посвящена описанию внутренних алгоритмов и структур, составляющих основу операционной системы (т. н. «ядро»), и объяснению их взаимосвязи с программным интерфейсом. Таким образом, она будет полезна для работающих в различных операционных средах. При работе с книгой было бы гораздо полезнее обращаться непосредственно к исходному тексту системных программ, но книгу можно читать и независимо от него.  Во-вторых, эта книга может служить в качестве справочного руководства для системных программистов, из которого последние могли бы лучше уяснить себе механизм работы ядра операционной системы и сравнить между собой алгоритмы, используемые в UNIX, и алгоритмы, используемые в других операционных системах. Наконец, программисты, работающие в среде UNIX, могут углубить свое понимание механизма взаимодействия программ с операционной системой и посредством этого прийти к написанию более эффективных и совершенных программ.

Морис Дж Бах , Морис Дж. Бах

ОС и Сети, интернет / ОС и Сети / Книги по IT