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.

<p>12.2. Функции mmap, munmap и msync</p>

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

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

2. Со специальными файлами для обеспечения неименованного отображения памяти (разделы 12.4 и 12.5).

3. С shm_open для создания участка разделяемой неродственными процессами памяти Posix.

#include sys/mman.h

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

/* Возвращает начальный адрес участка памяти в случае успешного завершения. MAP_FAILED – в случае ошибки */

Аргумент addr может указывать начальный адрес участка памяти процесса, в который следует отобразить содержимое дескриптора fd. Обычно ему присваивается значение нулевого указателя, что говорит ядру о необходимости выбрать начальный адрес самостоятельно. В любом случае функция возвращает начальный адрес сегмента памяти, выделенной для отображения.

Аргумент len задает длину отображаемого участка в байтах; участок может начинаться не с начала файла (или другого объекта), а с некоторого места, задаваемого аргументом offset. Обычно offset = 0. На рис. 12.5 изображена схема отображения объекта в память.

Рис. 12.5. Пример отображения файла в память

Защита участка памяти с отображенным объектом обеспечивается с помощью аргумента prot и констант, приведенных в табл. 12.1. Обычное значение этого аргумента — PROT_READ | PROT_WRITE, что обеспечивает доступ на чтение и запись.

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