Семафоры
Семафор – особая структура, содержащая число большее или равное нулю и управляющая цепочкой процессов, ожидающих особого состояния на данном семафоре. Хотя они и кажутся очень простыми, семафоры – это очень мощное средство, а потому, на самом деле, весьма сложное.
Семафоры используются для контроля доступа к ресурсам: число в семафоре представляет собой количество процессов, которые могут получить доступ к данным. Каждый раз, когда процесс обращается к данным, значение в семафоре, должно быть уменьшено на единицу, и увеличено, когда работа с данными будет прекращена. Если ресурс эксклюзивный, то есть к данным должен иметь доступ только один процесс, то начальное значение в семафоре следует установить единицей.
Семафоры можно использовать и для других целей, например для счётчика ресурсов. В этом случае число в семафоре – количество свободных ресурсов (например, количество свободных ячеек памяти).
Пусть имеется буфер, в который несколько процессов S1,...,Sn могут записывать, и только один процесс L может из него считывать. Также операции нельзя выполнять одновременно (в данный момент времени только один процесс должен оперировать с буфером). Очевидно, что процессы Si могут писать всегда, когда буфер не полон, а процесс L может читать, когда буфер не пуст.
Таким образом, необходимо три семафора: один управляет доступом к буферу, а два других следят за числом элементов в нём.
Учитывая, что доступ к буферу должен быть эксклюзивным, первый семафор будет бинарным (его значение будет нулём или единицей), в то время как второй и третий будут принимать значения, зависящие от размера буфера.
В библиотеке C, в SysV семафор создаёт функция semget(2)
int semget(key_t key, int nsems, int semflg)
где key – IPC ключ, nsems – число семафоров, которое нежно создать, и semflg – права доступа, закодированные в 12 бит: первые три бита отвечают за режим создания, остальные девять – права на запись и чтение для пользователя, группы и остальных. Таким образом, SysV создаёт сразу несколько семафоров, что уменьшает код.
--------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/ipc.h>
#include <linux/sem.h>
int main(void)
{
key_t key;
int semid;
key = ftok("/etc/fstab", getpid());
/* создать только один семафор: */
semid = semget(key, 1, 0666 | IPC_CREAT);
return 0;
}
--------------------------------------------------------------
Управление семафором происходит с помощью функции semctl(2),
int semctl(int semid, int semnum, int cmd, ...),
которая выполняет действие cmd на наборе семафоров semid или (если требуется командой) на одном семафоре с номером semnum.
В зависимости от команды, может понадобится указать ещё один аргумент следующего типа:
{
union semun
int val; /* значение для SETVAL */
struct semid_ds *buf; /* буферы для IPC_STAT, IPC_SET */
unsigned short *array; /* массивы для GETALL, SETALL */
/* часть, особенная для Linux: */
struct seminfo *__buf; /* буфер для IPC_INFO */
};
Чтобы изменить значение семафора, используется директива SETVAL, новое значение должно быть указано в semun.
[...]
/* создать только один семафор */
semid = semget(key, 1, 0666 | IPC_CREAT);
/* в семафоре 0 установить значение 1 */
arg.val = 1;
semctl(semid, 0, SETVAL, arg);
[...]
Удаление семафора и освобождение структуры, использовавшейся для управления им выполняет директива IPC_RMID. Она удаляет семафор и посылает сообщение об этом всем процессам, ожидающим доступа к ресурсу. Последний раз изменим программу:
[...]
/* в семафоре 0 установить значение 1 */
arg.val = 1;
semctl(semid, 0, SETVAL, arg);
/* удалить семафор */
semctl(semid, 0, IPC_RMID);
[...]
Использовать семафор можно с помощью процедуры semop(2),
int semop(int semid, struct sembuf *sops, unsigned nsops);
здесь semid – идентификатор набора семафоров, sops – массив, содержащий операции, которые необходимо произвести, nsops – число этих операций. Каждая операция представляется структурой sembuf.
unsigned short sem_num; short sem_op; short sem_flg;
т.е номером семафора в множестве (sem_num), операцией (sem_op) и флагом, устанавливающим режим ожидания; пока он будет нулём.
Операции, которые можно указать, являются целыми числами и подчиняются следующим правилам:
1. sem_op < 0
Если модуль значения в семафоре больше или равен модулю sem_op, то sem_op добавляется к значению в семафоре (т.е. значение в семафоре уменьшается). Если модуль sem_op больше, то процесс переходит в спящий режим, пока не будет достаточно ресурсов.
2. sem_op = 0. Процесс спит пока значение в семафоре не достигнет нуля.
3. sem_op > 0 Значение sem_op добавляется к значению в семафоре, используемый ресурс освобождается.
Следующая программа представляет пример использования семафоров, реализуя предыдущий пример с буфером для чего создается пять процессов W и один процесс R. Процессы W будут пытаться получить доступ к ресурсу (буферу), закрывая его через семафор, и, если буфер не полон, будут класть в него элемент и освобождать ресурс. Процесс R будет закрывать ресурс, брать из него элемент, если буфер не пуст, и разблокировать ресурс.
Чтение и запись в буфер на самом деле ненастоящие: так происходит потому, что каждый процесс выполняется в своей собственной области памяти и не может обращаться к памяти другого процесса. Это делает настоящее управление буфером шестью процессами невозможным, так как каждый процесс будет видеть свою копию буфера.
Первый семафор (с номером 0) действует как замок к буферу, и его максимальное значение равно единице, остальные два отвечают за переполнение и наличие элементов в буфере. Одним семафором этого не добиться.
Дата добавления: 2015-03-26; просмотров: 714;