13 shm_unlink(Px_ipc_name(argv[1])); /* ошибки игнорируются */
14 /* создание shm. установка размера, отображение, закрытие дескриптора */
15 fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
16 Ftruncate(fd, sizeof(struct shmstruct));
17 ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
18 MAP_SHARED, fd, 0);
19 Close(fd);
20 sem_unlink(Px_ipc_name(argv[2])); /* игнорируем ошибку */
21 mutex = Sem_open(Px_ipc_name(argv[2]), O_CREAT | O_EXCL, FILE_MODE, 1);
22 Sem_close(mutex);
23 exit(0);
24 }
13-19 Программа начинает работу с вызова shm_unlink, на тот случай, если объект разделяемой памяти еще существует, а затем делается вызов shm_open, создающий этот объект. Его размер устанавливается равным размеру структуры sbmstruct вызовом ftruncate, а затем mmap отображает объект в наше адресное пространство. После этого дескриптор объекта закрывается.
20-22 Сначала мы вызываем sem_unlink, на тот случай, если семафор еще существует. Затем делается вызов sem_open для создания именованного семафора и инициализации его единицей. Этот семафор будет использоваться в качестве взаимного исключения всеми процессами, которые будут обращаться к объекту разделяемой памяти. После выполнения этих операций семафор закрывается.
23 Процесс завершает работу. Поскольку разделяемая память Posix обладает по крайней мере живучестью ядра, объект не прекращает существования до тех пор, пока он не будет закрыт всеми открывавшими его процессами и явно удален.
Нам приходится использовать разные имена для семафора и объекта разделяемой памяти. Нет никаких гарантий, что в данной реализации к именам Posix IPC будут добавляться какие-либо суффиксы или префиксы, указывающие тип объекта (очередь сообщений, семафор, разделяемая память). Мы видели, что в Solaris эти типы имен имеют префиксы .MQ, .SEM и .SHM, но в Digital Unix они префиксов не имеют.
В листинге 13.7 приведен текст программы-клиента, которая увеличивает счетчик, хранящийся в разделяемой памяти, определенное число раз, блокируя семафор для каждой операции увеличения.
//pxshm/client1.c
1 #include "unpipc.h"
2 struct shmstruct { /* структура, помещаемая в разделяемую память */
3 int count;
4 };
5 sem_t *mutex; /* указатель на именованный семафор */
6 int
7 main(int argc, char **argv)
8 {
9 int fd, i, nloop;
10 pid_t pid;
11 struct shmstruct *ptr;
12 if (argc != 4)
13 err_quit("usage: client1
14 nloop = atoi(argv[3]);
15 fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR, FILE_MODE);
16 ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
17 MAP_SHARED, fd, 0);
18 Close(fd);
19 mutex = Sem_open(Px_ipc_name(argv[2]), 0);
20 pid = getpid();
21 for (i = 0; i < nloop; i++) {
22 Sem_wait(mutex);
23 printf("pid %ld: %d\n", (long) pid, ptr->count++);
24 Sem_post(mutex);
25 }
26 exit(0);
27 }
15-18 Вызов shm_open открывает объект разделяемой памяти, который должен уже существовать (поскольку не указан флаг O_CREAT). Память отображается в адресное пространство процесса вызовом mmap, после чего дескриптор закрывается.
19 Открываем именованный семафор.
20-26 Параметр командной строки позволяет указать количество увеличений счетчика. Каждый раз мы выводим предыдущее значение счетчика вместе с идентификатором процесса, поскольку одновременно работают несколько экземпляров программы.
Запустим сначала сервер, а затем три экземпляра программы-клиента в фоновом режиме.
solaris % server shm1 sem1