Чтение онлайн

ЖАНРЫ

Основы программирования в Linux
Шрифт:

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

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

Вывод двух разных символов будет обозначать

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

Упражнение 14.1. Семафоры

1. После системных директив

#include
вы включаете файл semun.h. Он определяет объединение типа
semun
в соответствии со стандартом X/Open, если оно уже не описано в системном файле sys/sem.h. Далее следуют прототипы функций и глобальная переменная, расположенные перед входом в функцию
main
. В ней создается семафор с помощью вызова
semget
, который возвращает ID семафора. Если программа вызывается первый раз (т.е. вызывается с параметром и
argc > 1
), выполняется вызов
set_semvalue
для инициализации семафора и переменной
op_char
присваивается значение
O
.

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <sys/sem.h>

#include "semun.h"

static int set_semvalue(void);

static void del_semvalue(void);

static int semaphore_p(void);

static int semaphore_v(void);

static int sem_id;

int main(int argc, char *argv[]) {

 int i;

 int pause_time;

 char op_char = 'О';

 srand((unsigned int)getpid);

 sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);

 if (argc >1) {

if (!set_semvalue) {

fprintf(stderr, "Failed to initialize semaphore\n");

exit(EXIT_FAILURE);

}

op_char = 'X';

sleep(2);

 }

2. Далее следует цикл, в котором 10 раз выполняется вход в критическую секцию и выход из нее. Вы сначала выполняете вызов функции

semaphore_p
, которая заставляет семафор ждать, когда эта программа будет готова войти в критическую секцию.

 for (i = 0; i < 10; i++) {

if (!semaphore_p) exit(EXIT_FAILURE);

printf("%c", op_char);

fflush(stdout);

pause_time = rand % 3;

sleep(pause_time);

printf("%c", op_char);

fflush(stdout);

3. После

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

if (!semaphore_v) exit(EXIT_FAILURE);

pause_time = rand % 2;

sleep(pause_time);

 }

 printf("\n%d - finished\n", getpid);

 if (argc > 1) {

sleep(10);

del_semvalue;

 }

 exit(EXIT_SUCCESS);

}

4. Функция

set_semvalue
инициализирует семафор с помощью команды
SETVAL
в вызове
semctl
. Это следует сделать перед использованием семафора.

static int set_semvalue(void) {

 union semun sem_union;

 sem_union.val = 1;

 if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);

 return(1);

}

5. У функции

del_semvalue
почти та же форма за исключением того, что в вызове
semctl
применяется команда
IPC_RMID
для удаления ID семафора.

static void del_semvalue(void) {

 union semun sem_union;

 if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)

fprintf(stderr, "Failed to delete semaphore\n");

}

6. Функция semaphore_p изменяет счетчик семафора на -1. Это операция ожидания или приостановки процесса.

static int semaphore_p(void) {

 struct sembuf sem_b;

 sem_b.sem_num = 0;

 sem_b.sem_op = -1; /* P */

 sem_b.sem_flg = SEM_UNDO;

 if (semop(sem_id, &sem_b, 1) == -1) {

fprintf(stderr, "semaphore_p failed\n");

return(0);

 }

 return(1);

}

7. Функция

semaphore_v
аналогична за исключением задания элемента
sem_op
структуры
sembuf
, равного 1. Это операция "освобождения", в результате которой семафор снова становится доступен.

Поделиться с друзьями: