solaris % client1 shm1 sem110000 &client1 shm1 sem110000 &client1 shm1 sem1 10000&
[2] 17976
[3] 17977
[4] 17978
pid 17977: 0
pid 17977: 1
. . .
pid 17977: 32
pid 17976: 33
. . .
pid 17976: 707
pid 17978: 708
. . .
pid 17978: 852
pid 17977: 853
. . .
pid 17977: 29997
pid 17977: 29999
Изменим наше решение задачи производителей и потребителей следующим образом. Сначала запускается сервер, создающий объект разделяемой памяти, в который клиенты записывают свои сообщения. Сервер просто выводит содержимое этих сообщений, хотя задачу можно и обобщить таким образом, чтобы он выполнял действия, аналогичные демону syslog, который описан в главе 13 [24]. Мы называем группу отправляющих сообщения процессов клиентами, потому что по отношению к нашему серверу они ими и являются, однако эти клиенты могут являться серверами по отношению к другим приложениям. Например, сервер Telnet является клиентом демона syslog, когда отправляет ему сообщения для занесения их в системный журнал.
Вместо передачи сообщений одним из описанных ранее методов (часть 2) будем хранить сообщения в разделяемой памяти. Это, разумеется, потребует какой-либо формы синхронизации действий клиентов, помещающих сообщения, и сервера, читающего их. На рис. 13.2 приведена схема приложения в целом.
Рис. 13.2. Несколько клиентов отправляют сообщения серверу через разделяемую память
Перед нами взаимодействие нескольких производителей (клиентов) и одного потребителя (сервер). Разделяемая память отображается в адресное пространство сервера и каждого из клиентов.
В листинге 13.8 приведен текст заголовочного файла cliserv2.h, в котором определена структура объекта, хранимого в разделяемой памяти.
//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 хранит индекс следующего помещаемого сообщения. Поскольку одновременно работают несколько производителей, эта переменная защищена взаимным исключением и хранится в разделяемой памяти вместе со всеми остальными.