Вывод двух разных символов будет обозначать вход в критическую секцию и выход из нее. Программа, запущенная с параметром, выводит X
при входе в критическую секцию и выходе из нее. Другие экземпляры запущенной программы будут выводить символ О
при входе в свои критические секции и выходе из них. Поскольку в любой заданный момент времени только один процесс способен войти в свою критическую секцию, все символы X
и O
должны появляться парами.
1. После системных директив #include
вы включаете файл semun.h. Он определяет объединение типа semun
в соответствии со стандартом X/Open, если оно уже не описано в системном файле sys/sem.h. Далее следуют прототипы функций и глобальная переменная, расположенные перед входом в функцию main
. В ней создается семафор с помощью вызова semget
, который возвращает ID семафора. Если программа вызывается первый раз (т.е. вызывается с параметром и argc > 1
), выполняется вызов set_semvalue
для инициализации семафора и переменной op_char
присваивается значение O
.
#include
#include
#include
#include
#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. Это операция "освобождения", в результате которой семафор снова становится доступен.
static int semaphore_v(void) {
struct sembuf sem_b;
sem_b.sem_num = 0;