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

ЖАНРЫ

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 <shmname> <semname> <#loops>");

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

solaris % client1 shm1 sem110000 &client1 shm1 sem110000 &client1 shm1 sem1 10000&

[2] 17976 интерпретатор выводит идентификаторы процессов

[3] 17977

[4] 17978

pid 17977: 0 и этот процесс запускается первым

pid 17977: 1

. . . процесс 17977 продолжает работу

pid 17977: 32

pid 17976: 33 ядро переключается междупроцессами

. . . процесс 17976 продолжает работу

pid 17976: 707

pid 17978: 708 ядро переключается между процессами

. . . процесс 17978 продолжает работу

pid 17978: 852

pid 17977: 853 ядро переключается
между процессами

. . . и т.д.

pid 17977: 29997

pid 17977: 29999 последнее выводимое значение. Оно оказывается правильным.

13.6. Отправка сообщений на сервер

Изменим наше решение задачи производителей и потребителей следующим образом. Сначала запускается сервер, создающий объект разделяемой памяти, в который клиенты записывают свои сообщения. Сервер просто выводит содержимое этих сообщений, хотя задачу можно и обобщить таким образом, чтобы он выполнял действия, аналогичные демону syslog, который описан в главе 13 [24]. Мы называем группу отправляющих сообщения процессов клиентами, потому что по отношению к нашему серверу они ими и являются, однако эти клиенты могут являться серверами по отношению к другим приложениям. Например, сервер Telnet является клиентом демона syslog, когда отправляет ему сообщения для занесения их в системный журнал.

Вместо передачи сообщений одним из описанных ранее методов (часть 2) будем хранить сообщения в разделяемой памяти. Это, разумеется, потребует какой-либо формы синхронизации действий клиентов, помещающих сообщения, и сервера, читающего их. На рис. 13.2 приведена схема приложения в целом.

Рис. 13.2. Несколько клиентов отправляют сообщения серверу через разделяемую память

Перед нами взаимодействие нескольких производителей (клиентов) и одного потребителя (сервер). Разделяемая память отображается в адресное пространство сервера и каждого из клиентов.

В листинге 13.8 приведен текст заголовочного файла cliserv2.h, в котором определена структура объекта, хранимого в разделяемой памяти.

Листинг 13.8. Заголовочный файл, определяющий содержимое разделяемой памяти

//pxshm/cliserv2.h

1 #include "unpipc.h"

2 #define MESGSIZE 256 /* максимальный размер сообщения в байтах, включая завершающий ноль */

3 #define NMESG 16 /* максимальное количество сообщений */

4 struct shmstruct { /* структура, хранящаяся в разделяемой памяти */

5 sem_t mutex; /* три семафора Posix, размещаемые в памяти */

6 sem_t nempty;

7 sem_t nstored;

8 int nput; /* индекс для следующего сообщения */

9 long noverflow; /* количество переполнений */

10 sem_t noverflowmutex; /* взаимное исключение для счетчика переполнений */

11 long msgoff[NMESG]; /* сдвиг для каждого из сообщений */

12 char msgdata[NMESG * MESGSIZE]; /* сами сообщения */

13 };

Основные семафоры и переменные

5-8 Три семафора Posix, размещаемых в памяти, используются для того же, для чего семафоры использовались в задаче производителей и потребителей в разделе 10.6. Их имена mutex, nempty, nstored. Переменная nput хранит индекс следующего помещаемого сообщения. Поскольку одновременно работают несколько производителей, эта переменная защищена взаимным исключением и хранится в разделяемой памяти вместе со всеми остальными.

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