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

ЖАНРЫ

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

Рис. 12.2. Копирование файла через разделяемую память

Этот сценарий иллюстрирует рис. 12.2.

Из этого рисунка видно, что копирование данных происходит всего лишь дважды: из входного файла в разделяемую память и из разделяемой памяти в выходной файл. Мы нарисовали два прямоугольника штриховыми линиями; они подчеркивают, что разделяемая память принадлежит как адресному пространству клиента, так и адресному пространству сервера.

Концепции, связанные с использованием разделяемой памяти через интерфейсы Posix и System V,

похожи. Первый интерфейс описан в главе 13, а второй — в главе 14.

В этой главе мы возвращаемся к примеру с увеличением последовательного номера, который впервые появился в главе 9. Теперь мы будем хранить последовательный номер в сегменте разделяемой памяти, а не в файле.

Сначала мы подчеркнем, что память разделяется между родительским и дочерним процессами при вызове fork. В пpoгрaммe из листинга 12.1 [1] родительский и дочерний процессы по очереди увеличивают глобальный целочисленный счетчик count.

1

Все исходные тексты, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com/download.

Листинг 12.1. Увеличение глобального счетчика родительским и дочерним процессами

//shm/incr1.c

1 #include "unpipc.h"

2 #define SEM_NAME "mysem"

3 int count = 0;

4 int

5 main(int argc, char **argv)

6 {

7 int i, nloop;

8 sem_t *mutex;

9 if (argc != 2)

10 err_quit("usage: incr1 <#loops>");

11 nloop = atoi(argv[1]);

12 /* создание, инициализация и удаление семафора */

13 mutex = Sem_open(Px_ipc_name(SEM_NAME), O_CREAT | O_EXCL, FILE_MODE, 1);

14 Sem_unlink(Px_ipc_name(SEM_NAME));

15 setbuf(stdout, NULL); /* stdout не буферизуется */

16 if (Fork == 0) { /* дочерний процесс */

17 for (i = 0; i < nloop; i++) {

18 Sem_wait(mutex);

19 printf("child: %d\n", count++);

20 Sem_post(mutex);

21 }

22 exit(0);

23 }

24 /* родительский процесс */

25 for (i = 0; i < nloop; i++) {

26 Sem_wait(mutex);

27 printf("parent: %d\r\", count++);

28 Sem_post(mutex);

29 }

30 exit(0);

31 }

Создание и инициализация семафора

12-14 Мы создаем и инициализируем семафор, защищающий переменную, которую мы считаем глобальной (count). Поскольку предположение о ее глобальности ложно, этот семафор на самом деле не нужен. Обратите внимание, что мы удаляем семафор из системы вызовом sem_unlink,

но хотя файл с соответствующим полным именем при этом и удаляется, на открытый в данный момент семафор эта команда не действует. Этот вызов мы делаем для того, чтобы файл был удален даже при досрочном завершении программы.

Отключение буферизации стандартного потока вывода и вызов fork

15 Мы отключаем буферизацию стандартного потока вывода, поскольку запись в него будет производиться и родительским, и дочерним процессами. Это предотвращает смешивание вывода из двух процессов.

16-29 Родительский и дочерний процессы увеличивают глобальный счетчик в цикле заданное число раз, выполняя операции только при установленном семафоре.

Если мы запустим эту программу на выполнение и посмотрим на результат, обращая внимание только на те строки, где система переключается между родительским и дочерним процессами, мы увидим вот что:

child: 0 дочерний процесс запущен первым,count=О

child; 1

child; 678

child: 679

parent: 0 дочерний процесс приостановлен, запускается родительский

процесс и отсчет начинается с О

parent: 1

parent: 1220

parent: 1221

child: 680 родительский процесс приостанавливается, начинает

выполняться дочерний процесс

child: 681

child: 2078

child: 2079

parent: 1222 дочерний процесс приостанавливается, начинает выполняться

родительский процесс

parent: 1223 и т. д.

Как видно, каждый из процессов использует собственную копию глобального счетчика count. Каждый начинает со значения 0 и при прохождении цикла увеличивает значение своей копии счетчика. На рис. 12.3 изображен родительский процесс перед вызовом fork.

Рис. 12.3. Родительский процесс перед вызовом fork

При вызове fork дочерний процесс запускается с собственной копией данных родительского процесса. На рис. 12.4 изображены оба процесса после возвращения из fork.

Рис. 12.4. Родительский и дочерний процессы после возвращения из fork

Мы видим, что родительский и дочерний процессы используют отдельные копии счетчика count.

12.2. Функции mmap, munmap и msync

Функция mmap отображает в адресное пространство процесса файл или объект разделяемой памяти Posix. Мы используем эту функцию в следующих ситуациях:

1. С обычными файлами для обеспечения ввода-вывода через отображение в память (раздел 12.3).

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