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, но хотя файл с соответствующим полным именем при этом и удаляется, на открытый в данный момент семафор эта команда не действует. Этот вызов мы делаем для того, чтобы файл был удален даже при досрочном завершении программы.
15 Мы отключаем буферизацию стандартного потока вывода, поскольку запись в него будет производиться и родительским, и дочерним процессами. Это предотвращает смешивание вывода из двух процессов.
16-29 Родительский и дочерний процессы увеличивают глобальный счетчик в цикле заданное число раз, выполняя операции только при установленном семафоре.
Если мы запустим эту программу на выполнение и посмотрим на результат, обращая внимание только на те строки, где система переключается между родительским и дочерним процессами, мы увидим вот что:
child: 0
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.
Функция mmap отображает в адресное пространство процесса файл или объект разделяемой памяти Posix. Мы используем эту функцию в следующих ситуациях:
1. С обычными файлами для обеспечения ввода-вывода через отображение в память (раздел 12.3).
2. Со специальными файлами для обеспечения неименованного отображения памяти (разделы 12.4 и 12.5).
3. С shm_open для создания участка разделяемой неродственными процессами памяти Posix.
#include
void *mmap(void
/* Возвращает начальный адрес участка памяти в случае успешного завершения. MAP_FAILED – в случае ошибки */
Аргумент
Аргумент
Рис. 12.5. Пример отображения файла в память
Защита участка памяти с отображенным объектом обеспечивается с помощью аргумента
Таблица 12.1. Аргумент prot для вызова mmap