Создание объекта разделяемой памяти

10-16 Сначала делается вызов shm_unlink, чтобы удалить объект с тем же именем, который мог остаться после другого приложения. Затем объект разделяемой памяти создается вызовом shm_open и отображается в адресное пространство процесса вызовом mmap, после чего дескриптор объекта закрывается.

Инициализация массива сдвигов

17-19 Массив сдвигов инициализируется сдвигами сообщений.

Инициализация семафоров

20-24 Инициализируются четыре семафора, размещаемые в объекте разделяемой памяти. Второй аргумент sem_init всегда делается ненулевым, поскольку семафоры будут использоваться совместно несколькими процессами.

Ожидание сообщения, вывод его содержимого

25-36 Первая половина цикла for написана по стандартному алгоритму потребителя: ожидание изменения семафора nstored, установка блокировки для семафора mutex, обработка данных, увеличение значения семафора nempty.

Обработка переполнений

37-43 При каждом проходе цикла мы проверяем наличие возникших переполнений. Сравнивается текущее значение noverflows с предыдущим. Если значение изменилось, оно выводится на экран и сохраняется. Обратите внимание, что значение считывается с заблокированным взаимным исключением noverflowmutex, но блокировка снимается перед сравнением и выводом значения. Идея в том, что нужно всегда следовать общему правилу минимизации количества операций, выполняемых с заблокированным взаимным исключением. В листинге 13.10 приведен текст программы-клиента.

Листинг 13.10. Клиент, помещающий сообщения в разделяемую память

//pxshm/client2.c

1  #include "cliserv2.h"

2  int

3  main(int argc, char **argv)

4  {

5   int fd, i, nloop, nusec;

6   pid_t pid;

7   char mesg[MESGSIZE];

8   long offset;

9   struct shmstruct *ptr;

10  if (argc != 4)

11   err_quit("usage: client2 name #loops #usec");

12  nloop = atoi(argv[2]);

13  nusec = atoi(argv[3]);

14  /* открытие и отображение объекта разделяемой памяти, созданного сервером заранее */

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  pid = getpid;

20  for (i = 0; i nloop; i++) {

21   Sleep_us(nusec);

22   snprintf(mesg, MESGSIZE, "pid %ld; message %d", (long) pid, i);

23   if (sem_trywait(ptr-nempty) == –1) {

24    if (errno == EAGAIN) {

25     Sem_wait(ptr-noverflowmutex);

26     ptr-noverflow++;

27     Sem_post(ptr-noverflowmutex);

28     continue;

29    } else

30     err_sys("sem_trywait error");

31   }

32   Sem_wait(ptr-mutex);

33   offset = ptr-msgoff[ptr-nput];

34   if (++(ptr-nput) = NMESG)

35    ptr-nput = 0; /* циклический буфер */

36   Sem_post(ptr-mutex);

37   strcpy(ptr-msgdata[offset], mesg);

38   Sem_post(ptr-nstored);

39  }

40  exit(0);

41 }

Аргументы командной строки

10-13 Первый аргумент командной строки задает имя объекта разделяемой памяти; второй — количество сообщений, которые должны быть отправлены серверу данным клиентом. Последний аргумент задает паузу перед отправкой очередного сообщения (в микросекундах). Мы сможем получить ситуацию переполнения, запустив одновременно несколько экземпляров клиентов и указав небольшое значение для этой паузы. Таким образом мы сможем убедиться, что сервер корректно обрабатывает ситуацию переполнения.

Открытие и отображение разделяемой памяти

14-18 Мы открываем объект разделяемой памяти, предполагая, что он уже создан и проинициализирован сервером, а затем отображаем его в адресное пространство процесса. После этого дескриптор может быть закрыт.

Отправка сообщений
Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже