При использовании функции sem_open() для открытия семафора ей нужно передать всего два аргумента. Но в случае указания флага O_CREAT еще два аргумента становятся обязательными: mode и value (если семафор с именем name уже существует, то оба этих аргумента игнорируются). Они имеют следующее назначение.
• Аргумент mode — это битовая маска, которая определяет права доступа к новому семафору. Здесь применяются те же битовые значения, что и для файлов (см. табл. 15.4); как и в случае с вызовом open(), к маске применяется атрибут umask (см. подраздел 15.4.6). Стандарт SUSv3 не описывает никаких флагов для аргумента oflag, определяющих режим доступа (O_RDONLY, O_WRONLY и O_RDWR). Во многих системах, в том числе и в Linux, при открытии семафора по умолчанию используется режим доступа O_RDWR, так как большинство приложений выполняют как чтение, так и изменение семафоров, что подразумевает применение функций sem_post() и sem_wait(). То есть каждой категории пользователей, которым нужно работать с семафорами (владельцу, группе и т. д.) следует выдать права на чтение и запись.
• Аргумент value является беззнаковым целым числом, определяющим начальное значение нового семафора. Создание и инициализация семафора происходит автоматически.
Вне зависимости от того, создается ли новый семафор или открывается уже существующий, функция sem_open() возвращает указатель на значение типа sem_t, которое будет использоваться в последующих вызовах для работы с семафором. В случае неудачи sem_open() возвращает ошибку SEM_FAILED (в большинстве реализаций она определена как ((sem_t *) 0) или ((sem_t *) —1); в Linux применяется первый вариант).
Стандарт SUSv3 гласит, что при попытке выполнения операций (sem_post(), sem_wait() и т. д.) с
sem_t *sp, sem2
sp = sem_open(…);
sem2 = *sp;
sem_wait(&sem2);
Потомок, созданный с помощью вызова fork(), наследует ссылки на все именованные семафоры, открытые его родителем. После этого родительский и дочерний процессы могут задействовать данные семафоры для синхронизации своих действий.
Программа, показанная в листинге 49.1, предоставляет простой интерфейс командной строки к функции sem_open(). В функции usageError() представлен формат команд для этой программы.
В следующей сессии командной строки демонстрируется использование данного примера. Сначала мы вызываем команду umask, чтобы полностью закрыть доступ для всех остальных пользователей. Затем создаем семафор, доступный лишь нам, и выводим содержимое виртуального каталога (доступного только в Linux), который хранит именованные семафоры.
$ umask 007
$ ./psem_create — cx /demo 666
$ ls — l /dev/shm/sem.*
— rw-rw- 1 mtk users 16 Jul 6 12:09 /dev/shm/sem.demo
Вывод команды ls показывает: атрибут umask переопределил права доступа, разрешив чтение и запись остальным пользователям.
Если мы еще раз используем то же имя, чтобы создать доступный только нам семафор, то ничего не получится, поскольку данное имя уже занято.
$ ./psem_create — cx /demo 666
ERROR [EEXIST File exists] sem_open
Листинг 49.1. Использование функции sem_open() для открытия или создания именованного POSIX-семафора
psem/psem_create.c
#include
#include
#include
#include "tlpi_hdr.h"
static void
usageError(const char *progName)
{
fprintf(stderr, "Usage: %s [-cx] name
[octal-perms [value]]\n", progName);
fprintf(stderr, " — c Create semaphore (O_CREAT)\n");
fprintf(stderr, " — x Create exclusively (O_EXCL)\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int flags, opt;
mode_t perms;
unsigned int value;
sem_t *sem;
flags = 0;
while ((opt = getopt(argc, argv, "cx"))!= -1) {
switch (opt) {
case 'c': flags |= O_CREAT; break;
case 'x': flags |= O_EXCL; break;
default: usageError(argv[0]);
}
}
if (optind >= argc)
usageError(argv[0]);
/* По умолчанию используются права доступа rw-,
а начальное значение семафора равно 0 */
perms = (argc <= optind + 1)? (S_IRUSR | S_IWUSR):
getInt(argv[optind + 1], GN_BASE_8, "octal-perms");
value = (argc <= optind + 2)? 0: getInt(argv[optind + 2], 0, "value");
sem = sem_open(argv[optind], flags, perms, value);
if (sem == SEM_FAILED)
errExit("sem_open");
exit(EXIT_SUCCESS);
}
psem/psem_create.c
49.2.2. Закрытие семафора