ГЛАВА 12 Введение в разделяемую память

ГЛАВА 12

Введение в разделяемую память

12.1. Введение

Разделяемая память является наиболее быстрым средством межпроцессного взаимодействия. После отображения области памяти в адресное пространство процессов, совместно ее использующих, для передачи данных между процессами больше не требуется участие ядра. Обычно, однако, требуется некоторая форма синхронизации процессов, помещающих данные в разделяемую память и считывающих ее оттуда. В части 3 мы обсуждали различные средства синхронизации: взаимные исключения, условные переменные, блокировки чтения-записи, блокировки записей и семафоры.

ПРИМЕЧАНИЕ

Говоря «не требуется участие ядра», мы подразумеваем, что процессы не делают системных вызовов для передачи данных. Очевидно, что все равно именно ядро обеспечивает отображение памяти, позволяющее процессам совместно ею пользоваться, и затем обслуживает эту память (обрабатывает сбои страниц и т. п.).

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

? Сервер считывает данные из входного файла. Данные из файла считываются ядром в свою память, а затем копируются из ядра в память процесса.

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

ПРИМЕЧАНИЕ

Мы говорим «обычно», поскольку очереди сообщений Posix могут быть реализованы через отображение файла в память (функцию mmap мы опишем в этой главе), как мы показали в разделе 5.8 и в решении упражнения 12.2. На рис. 12.1 мы предполагаем, что очереди сообщений Posix реализованы в ядре, что также возможно. Но именованные и неименованные каналы и очереди сообщений System V требуют копирования данных из процесса в ядро вызовом write или msgsnd или копирования данных из ядра процессу вызовом read или msgrcv. 

? Клиент считывает данные из канала IPC, что обычно требует их копирования из ядра в пространство процесса.

? Наконец, данные копируются из буфера клиента (второй аргумент вызова write) в выходной файл.

Таким образом, для копирования файла обычно требуются четыре операции копирования данных. К тому же эти операции копирования осуществляются между процессами и ядром, что часто является дорогостоящей операцией (более дорогостоящей, чем копирование данных внутри ядра или внутри одного процесса). На рис. 12.1 изображено перемещение данных между клиентом и сервером через ядро. 

Рис. 12.1. Передача содержимого файла от сервера к клиенту

Недостатком этих форм IPC — именованных и неименованных каналов — является то, что для передачи между процессами информация должна пройти через ядро.

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

Теперь информация передается между клиентом и сервером в такой последовательности:

? сервер получает доступ к объекту разделяемой памяти, используя для синхронизации семафор (например);

? сервер считывает данные из файла в разделяемую память. Второй аргумент вызова read (адрес буфера) указывает на объект разделяемой памяти;

? после завершения операции считывания клиент уведомляется сервером с помощью семафора;

? клиент записывает данные из объекта разделяемой памяти в выходной файл. 

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

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

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

Концепции, связанные с использованием разделяемой памяти через интерфейсы Posix и System V, похожи. Первый интерфейс описан в главе 13, а второй — в главе 14.

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

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

Листинг 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 ", 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 ", 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.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

ГЛАВА 1 Введение

Из книги Самоучитель UML автора Леоненков Александр

ГЛАВА 1 Введение Если попытаться охарактеризовать современный уровень развития компьютерных и информационных технологий, то первое, на что следует обратить внимание – это возрастающая сложность не только отдельных физических и программных компонентов, но и лежащих в


Глава 1 Введение

Из книги Секреты и ложь. Безопасность данных в цифровом мире автора Шнайер Брюс


СОФТЕРРА: Память на лица, или Лица на память

Из книги Журнал «Компьютерра» № 36 от 3 октября 2006 года автора Журнал «Компьютерра»

СОФТЕРРА: Память на лица, или Лица на память Автор: Алексей КлимовВышла девятая версия ACDSee. Судя по объему нововведений, это не «Девятый вал» Айвазовского [Иван Айвазовский, «Девятый вал». 1850 г] и даже не «9 рота» Бондарчука [Федор Бондарчук, «9 рота». 2005 г]. Поэтому в обзоре


Глава 1. Введение

Из книги Iptables Tutorial 1.1.19 автора Andreasson Oskar

Глава 1. Введение 1.1. Почему было написано данное руководство Скажем так, я посчитал, что существует досадный пробел в HOWTO по части информации об iptables и функциях сетевого фильтра (netfilter), реализованных в новой серии ядер 2.4.x Linux. Кроме всего прочего, я попытался ответить на


Глава 4 «Мозги» и память компьютера

Из книги Железо ПК [Популярный самоучитель] автора Пташинский Владимир

Глава 4 «Мозги» и память компьютера Не бывает сложных программ. Бывает мало памяти. Компьютерная примета В предыдущей главе мы познакомились с такими важными комплектующими, как корпус, блок питания и материнская плата. И если их со всей ответственностью можно назвать


Глава 6 Внешняя память

Из книги Фреймы для представления знаний автора Мински Марвин

Глава 6 Внешняя память Что-то с памятью моей стало… Стенания над сломанной «флешкой» В одной из предыдущих глав мы познакомились с двумя видами памяти, которой обладает компьютер. Как вы помните, оперативная память предназначена для кратковременного хранения


Глава третья Обучение, память и парадигмы[1]

Из книги UNIX: взаимодействие процессов автора Стивенс Уильям Ричард

Глава третья Обучение, память и парадигмы[1] «Природа дает ребенку различные средства для исправления всяческих ошибок, которые он может совершить по отношению к окружающим его предметам. При каждой возможности его взгляды корректируются опытом; неудача и боль являются


ГЛАВА 13 Разделяемая память Posix

Из книги Технология XSLT автора Валиков Алексей Николаевич

ГЛАВА 13 Разделяемая память Posix 13.1. Введение В предыдущей главе рассматривались общие вопросы, связанные с разделяемой памятью, и детально разбиралась функция mmap. Были приведены примеры, в которых вызов mmap использовался для создания области памяти, совместно


ГЛАВА 14 Разделяемая память System V

Из книги Руководство по переходу на Ubuntu 10.04 LTS «Lucid Lynx» автора Неворотин Вадим

ГЛАВА 14 Разделяемая память System V 14.1. Введение Основные принципы разделяемой памяти System V совпадают с концепцией разделяемой памяти Posix. Вместо вызовов shm_open и mmap в этой системе используются вызовы shmget и shmat.Для каждого сегмента разделяемой памяти ядро хранит нижеследующую


14.7. Ограничения, накладываемые на разделяемую память

Из книги Linux глазами хакера автора Флёнов Михаил Евгеньевич

14.7. Ограничения, накладываемые на разделяемую память На разделяемую память System V накладываются определенные ограничения точно так же, как и на семафоры и очереди сообщений System V (раздел 3.8). В табл. 14.1 приведены значения этих ограничений для разных реализаций. В первом


Глава 1. Введение в XML

Из книги автора

Глава 1. Введение в XML Первая глава книги об XSLT не случайно посвящена языку XML (от англ. extensible Markup Language — расширяемый язык разметки). XML — это фундаментальная концепция, по отношению к которой XSLT является прикладной технологией и поэтому для эффективного применения XSLT нужно


Глава 1 Введение в XML

Из книги автора

Глава 1 Введение в XML Что такое XML? За последние несколько десятков лет, прошедших с создания первых электронных устройств, в игру с природой человеком была введена третья сторона — вычислительные машины. Человек постепенно доверил им свою память, переложил на них сложные


Глава 1 Введение

Из книги автора

Глава 1 Введение Что такое Ubuntu? Ubuntu — это современная полнофункциональная операционная система, основанная на ядре Linux. В переводе с южноафриканского языка зулу слово Ubuntu примерно означает «человечность».Ubuntu распространяется и всегда будет распространяться абсолютно


Глава 1 Введение

Из книги автора

Глава 1 Введение Однажды я показывал администратору ОС Windows, как устанавливать и работать с Linux. Сам процесс инсталляции ему понравился, потому что в последних версиях он достаточно прост. Но когда мы установили и решили настроить Samba-сервер, последовала куча вопросов типа: