Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
28
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Семафоры

Семафор – это счетчик, который способствует предотвращению одновременного доступа нескольких процессов или потоков к совместно используемому ресурсу. Если процесс или поток не проверяют состояние семафора перед выполнением операций с совместно используемым ресурсом, последствия могут оказаться самыми печальными.

Двоичный семафор имеет два состояния: закрыто и открыто. В общем случае семафоры могут иметь если не бесконечное, то достаточно большое число состояний. По сути это обычный счетчик. Он уменьшается при захвате семафора процессом (запирается) и увеличивается при освобождении (отпирается). Если счетчик равен нулю, процесс, пытающийся захватить семафор, должен подождать, пока другой процесс не освободит его, увеличив значение счетчика - значение семафора не может быть отрицательным числом. Над семафорами обычно выполняются два действия, которые абстрактно можно представить как semwait и sempost. Выразим эти операции на языке С:

void semwait(int *sem)

{

while (*sem <= 0)

; /* просто ждать, ничего не делая*/

(*sem)-;

}

void sempost(int *sem)

{

(*sem)++;

}

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

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

Для ускорения работы с семафорами можно напрямую объявить объект sem_t в программе: sem_t sem; или разместить в динамической памяти: sem_t *semp = malloc(sizeof(sem_t));

Если объект размещается таким образом, необходимо инициализировать его вызовом sem_init:

sem_init - инициализирует неименованный семафор

#include <semaphore.h>

int sem_init (

sem_t *sem, /* семафор */

int pshared, /*доступен другим процессам */

unsigned value /* начальное значение */

);

/* Возвращает 0 в случае успеха или -1 в случае ошибки (код ошибки - в errno) */

Для разрушения неименованного семафора следует использовать системный вызов sem_destroy:

sem_destroy - разрушает неименованный семафор

#include <semaphore.h>

int sem_ destroy (

sem_t *sem /* семафор */

);

/* Возвращает 0 в случае успеха или -1 в случае ошибки (код ошибки - в errno) */

Неименованные семафоры работают быстрее и это дает нам вот что:

  • они прекрасно работают с потоками, особенно когда нужен семафор со счетчиком;

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

Основная область применений неименованных семафоров – работа с потоками, особенно в Linux.