В листинге 11.5 приведен текст программы semops, позволяющей выполнять последовательность действий над набором семафоров.
7-19 Параметр –n соответствует установленному флагу IPC_NOWAIT для каждой операции, а параметр –u аналогичным образом позволяет указать для каждой операции флаг SEM_UNDO. Обратите внимание, что функция semop позволяет указывать свой набор флагов для каждого элемента структуры sembuf (то есть для каждой из операций в отдельности), но для простоты мы в нашей программе задаем одинаковые флаги для всех операций.
20-29 После открытия семафора вызовом semget мы выделяем память под массив структур sembuf, по одному элементу на каждую операцию из командной строки. В отличие от предыдущих двух программ эта позволяет пользователю задать меньше команд, чем имеется семафоров в наборе.
30 Вызов semop выполняет последовательность операций над семафорами набора.
//svsem/semops.c
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 int с, i, flag, semid, nops;
6 struct sembuf *ptr;
7 flag = 0;
8 while ((c = Getopt(argc, argv, "nu")) != –1) {
9 switch (c) {
10 case 'n':
11 flag |= IPC_NOWAIT; /* для всех операций */
12 break;
13 case 'u':
14 flag |= SEM_UNDO; /* для всех операций */
15 break;
16 }
17 }
18 if (argc = optind < 2) /* argc – optind = количество оставшихся аргументов */
19 err_quit("usage: semops [ –n ] [ –u ]
20 semid = Semget(Ftok(argv[optind], 0), 0, 0);
21 optind++;
22 nops = argc – optind;
23 /* выделение памяти под операции, сохранение их в массиве и выполнение */
24 ptr = Calloc(nops, sizeof(struct sembuf));
25 for (i = 0; i < nops; i++) {
26 ptr[i].sem_num = i;
27 ptr[i].sem_op = atoi(argv[optind + i]); /* <0, 0, or >0 */
28 ptr[i].sem_flg = flag;
29 }
30 Semop(semid, ptr, nops);
31 exit(0);
32 }
Примеры
Теперь мы продемонстрируем работу пяти приведенных выше программ и исследуем некоторые свойства семафоров System V:
solaris % touch /tmp/rich
solaris % semcreate –e /tmp/rich 3
solaris % semsetvalues /tmp/rich 1 2 3
solaris % semgetvalues /tmp/rich
semval[0] = 1
semval[1] = 2
semval[2] = 3
Сначала мы создали файл с именем /tmp/rich, который использовался при вызове ftok для вычисления идентификатора набора семафоров. Программа semcreate создает набор с тремя элементами. Программа semsetvalues устанавливает значения этих элементов (1, 2 и 3), a semgetvalues выводит их значения.
Теперь продемонстрируем атомарность выполнения последовательности операций над набором:
solaris % semops –n /tmp/rich –1 –2 –4
semctl error: Resource temporarily unavailable
solaris % semgetvalues /tmp/rich
semval[0] = 1
semval[1] = 2
semval[2] = 3