Стивенс Уильям Ричард
Шрифт:
Теперь информация передается между клиентом и сервером в такой последовательности:
■ сервер получает доступ к объекту разделяемой памяти, используя для синхронизации семафор (например);
■ сервер считывает данные из файла в разделяемую память. Второй аргумент вызова read (адрес буфера) указывает на объект разделяемой памяти;
■ после завершения операции считывания клиент уведомляется сервером с помощью семафора;
■ клиент записывает данные из объекта разделяемой памяти в выходной файл.
Рис. 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-14 Мы создаем и инициализируем семафор, защищающий переменную, которую мы считаем глобальной (count). Поскольку предположение о ее глобальности ложно, этот семафор на самом деле не нужен. Обратите внимание, что мы удаляем семафор из системы вызовом sem_unlink, но хотя файл с соответствующим полным именем при этом и удаляется, на открытый в данный момент семафор эта команда не действует. Этот вызов мы делаем для того, чтобы файл был удален даже при досрочном завершении программы.
15 Мы отключаем буферизацию стандартного потока вывода, поскольку запись в него будет производиться и родительским, и дочерним процессами. Это предотвращает смешивание вывода из двух процессов.
16-29 Родительский и дочерний процессы увеличивают глобальный счетчик в цикле заданное число раз, выполняя операции только при установленном семафоре.
Если мы запустим эту программу на выполнение и посмотрим на результат, обращая внимание только на те строки, где система переключается между родительским и дочерним процессами, мы увидим вот что: