Приведем теперь пример (листинг 13.5), иллюстрирующий тот факт, что объект разделяемой памяти может отображаться в области, начинающиеся с разных адресов в разных процессах.

Листинг 13.5. Разделяемая память может начинаться с разных адресов в разных процессах

//pxshm/test3.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   int fd1, fd2, *ptr1, *ptr2;

6   pid_t childpid;

7   struct stat stat;

8   if (argc != 2)

9    err_quit("usage: test3 name");

10  shm_unlink(Px_ipc_name(argv[1]));

11  fd1 = Shm_open(Px_ipc_name(argv[1]), O_RDWR | O_CREAT | O_EXCL, FILE_MODE);

12  Ftruncate(fd1, sizeof(int));

13  fd2 = Open("/etc/motd", O_RDONLY);

14  Fstat(fd2, stat);

15  if ((childpid = Fork) == 0) {

16   /* дочерний процесс */

17   ptr2 = Mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);

18   ptr1 = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,

19    MAP_SHARED, fd1, 0);

20   printf("child: shm ptr = %p, motd ptr = %p\n", ptr1, ptr2);

21   sleep(5);

22   printf("shared memory integer = %d\n", *ptr1);

23   exit(0);

24  }

25  /* родительский процесс: вызовы map следуют в обратном порядке */

26  ptr1 = Mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);

27  ptr2 = Mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);

28  printf("parent: shm ptr = %p, motd ptr = %p\n", ptr1, ptr2);

29  *ptr1 = 777;

30  Waitpid(childpid, NULL, 0);

31  exit(0);

32 }

10-14 Создаем сегмент разделяемой памяти с именем, принимаемым в качестве аргумента командной строки. Его размер устанавливается равным размеру целого. Затем открываем файл /etc/motd.

15-30 После вызова fork и родительский, и дочерний процессы вызывают mmap дважды, но в разном порядке. Каждый процесс выводит начальный адрес каждой из областей памяти. Затем дочерний процесс ждет 5 секунд, родительский процесс помещает значение 777 в область разделяемой памяти, после чего дочерний процесс считывает и выводит это значение.

Запустив эту программу, мы убедимся, что объект разделяемой памяти начинается с разных адресов в пространствах дочернего и родительского процессов:

solaris % test3 test3.data

parent: shm ptr = eee30000, motd ptr = eee20000

child: shm ptr = eee20000, motd ptr = eee30000

shared memory integer = 777

Несмотря на разницу в начальных адресах, родительский процесс успешно помещает значение 777 по адресу 0xeee30000, а дочерний процесс благополучно считывает его по адресу 0хеее20000. Указатели ptr1 в родительском и дочернем процессах указывают на одну и ту же область разделяемой памяти, хотя их значения в этих процессах различны.

<p>13.5. Увеличение общего счетчика</p>

Разработаем программу, аналогичную приведенной в разделе 12.3, — несколько процессов увеличивают счетчик, хранящийся в разделяемой памяти. Итак, мы помещаем счетчик в разделяемую память, а для синхронизации доступа к нему используем именованный семафор. Отличие программы из этого раздела от предыдущей состоит в том, что процессы более не являются родственными. Поскольку обращение к объектам разделяемой памяти Posix и именованным семафорам Posix осуществляется по именам, процессы, увеличивающие общий счетчик, могут не состоять в родстве. Достаточно лишь, чтобы каждый из них знал имя IPC счетчика и чтобы у каждого были соответствующие разрешения на доступ к объектам IPC (области разделяемой памяти и семафору).

В листинге 13.6 приведен текст программы-сервера, которая создает объект разделяемой памяти, затем создает и инициализирует семафор, после чего завершает работу.

Листинг 13.6. Программа, создающая и инициализирующая объект разделяемой памяти и семафор

//pxshm/server1.c

1  #include "unpipc.h"

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