
- •Часть 4. Локальное взаимодействие процессов
- •Глава 16. Блокирование записей 89
- •12.2. Процессы, потоки и общий доступ к информации
- •12.3. Живучесть объектов ipc
- •12.4. Пространства имен
- •12.5. Действие команд fork, exec и exit на объекты ipc
- •12.6. Комментарии к примерам ipc
- •12.7. Выводы по главе 12
- •12.8. Упражнения по главе 12
- •Глава 13. Именованные и неименованные каналы
- •13.1. Введение
- •13.2. Приложение типа клиент-сервер
- •13.3. Программные каналы
- •13.4. Функции popen и pclose
- •13.5. Именованные каналы (fifo)
- •13.6. Некоторые свойства именованных и неименованных каналов
- •13.7. Один сервер, несколько клиентов
- •13.8. Последовательные и параллельные серверы
- •13.9. Ограничения программных каналов и fifo
- •13.10. Выводы по главе 13
- •13.11. Упражнения по главе 13
- •Глава 14. Программные потоки
- •14.1. Введение
- •14.2. Концепция потоков
- •14.3. Идентификация потоков
- •14.4. Создание потока
- •14.5. Завершение потока
- •Функции управления процессами и потоками
- •14.6. Установка атрибутов потока
- •14.7. Реентерабельность
- •Альтернативные версии функций, безопасные в многопоточной среде
- •14.8. Локальные данные потоков
- •14.9. Принудительное завершение потоков
- •Некоторые точки выхода, определенные стандартом Posix.1
- •14.10. Потоки и сигналы
- •14.11. Выводы по главе 14
- •14.12. Упражнения по главе 14 Глава 15. Средства синхронизации потоков
- •15.1. Введение
- •15.2. Взаимные исключения: установка и снятие блокировки
- •15.2.1. Схема производитель-потребитель
- •15.2.2. Блокирование и опрос
- •15.2.3. Предотвращение тупиковых ситуаций
- •15.3. Условные переменные
- •15.3.1. Ожидание и сигнализация
- •15.3.2. Исключение состояния гонок
- •15.4. Блокировки чтения-записи
- •15.5. Атрибуты средств синхронизации потоков
- •15.5.1. Атрибуты взаимных исключений
- •Поведение взаимных исключений различных типов
- •15.5.2. Атрибуты условных переменных
- •15.5.3. Атрибуты блокировок чтения-записи
- •15.6. Выводы по главе 15
- •15.7. Упражнения по главе 15
- •Глава 16. Блокирование записей
- •16.1. Введение
- •16.2. Блокирование записей и файлов
- •16.3. Блокирование записей с помощью fcntl по стандарту Posix
- •16.4. Рекомендательная блокировка
- •16.5. Обязательная блокировка
- •16.6. Приоритет чтения и записи Выводы по главе 16
- •Упражнения по главе 16 Глава 17. System V ipc
- •17.1. Введение
- •17.2. Ключи типа key_t и функция ftok
- •17.3. Структура ipc_perm
- •17.4. Создание и открытие каналов ipc
- •17.5. Разрешения ipc
- •17.6. Программы ipcs и ipcrm
- •17.7. Ограничения ядра
- •17.8. Выводы по главе 17
- •17.9. Упражнения по главе 17
- •Глава 18. Очереди сообщений System V
- •18.1. Введение
- •18.2. Функция msgget
- •18.3. Функция msgsnd
- •18.4. Функция msgrcv
- •18.5. Функция msgctl
- •18.6. Пример программы клиент-сервер
- •18.7. Мультиплексирование сообщений
- •18.7.1. Пример: одна очередь на приложение
- •18.7.2. Пример: одна очередь для каждого клиента
- •18.8. Ограничения, накладываемые на очереди сообщений
- •18.9. Выводы по главе 18
- •18.10. Упражнения по главе 18
- •Глава 19. Семафоры System V
- •19.1. Введение
- •19.2. Функция semget
- •19.3. Функция semop
- •19.4. Функция semctl
- •19. . Ограничения семафоров System V
- •19. . Выводы по главе 19
- •19. . Упражнения по главе 19 Глава 20. Введение в разделяемую память
- •20.1. Введение
- •20.2. Функции mmap, munmap и msync
- •20.3. Увеличение счетчика в отображаемом в память файле
- •20.4. Неименованное отображение в память
- •20.5. Обращение к объектам, отображенным в память
- •20.6. Выводы по главе 20
- •20.7. Упражнения по главе 20
- •Глава 21. Разделяемая память System V
- •21.1. Введение
- •21.2. Функция shmget
- •21.3. Функция shmat
- •21.4. Функция shmdt
- •21.5. Функция shmctl
- •21.6. Ограничения, накладываемые на разделяемую память
- •21.7. Выводы по главе 21
- •21.8. Упражнения по главе 21
20.2. Функции mmap, munmap и msync
Функция mmapотображает файл в адресное пространство процесса. Мы используем эту функцию в следующих ситуациях:
С обычными файлами для обеспечения ввода-вывода через отображение в память (раздел 19.3).
Со специальными файлами для обеспечения неименованного отображения памяти (разделы 19.4 и 19.5).
#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. На рис.19.3изображена схема отображения файла в память.
рис. 19.3
Защита участка памяти с отображенным файлом обеспечивается с помощью аргумента protи констант, приведенных в табл.19.1. Обычное значение этого аргумента –PROT_READ | PROT_WRITE, что обеспечивает доступ на чтение и запись.
Таблица 19.1
Аргумент protдля вызоваmmap
prot |
Описание |
PROT_READ |
Данные могут быть считаны |
PROT_WRITE |
Данные могут быть записаны |
PROT_EXEC |
Данные могут быть выполнены |
PROT_NONE |
Доступ к данным закрыт |
Таблица 19.2
Аргумент flagдля вызоваmmap
flag |
Описание |
MAP_SHARED |
Изменения передаются другим процессам |
MAP_PRIVATE |
Изменения не передаются другим процессам и не влияют на отображенный файл |
MAP_FIXED |
Аргумент addrинтерпретируется как адрес памяти |
Аргумент flagsможет принимать значения из табл.19.2. Можно указать только один из флагов –MAP_SHAREDилиMAP_PRIVATE, прибавив к нему при необходимостиMAP_FIXED. Если указан флагMAP_PRIVATE, все изменения будут производиться только с образом файла в адресном пространстве процесса; другим процессам они доступны не будут. Если же указан флагMAP_SHARED, изменения отображаемых данных видны всем процессам, совместно использующим файл.
Одним из способов добиться совместного использования памяти родительским и дочерним процессами является вызов mmapс флагомMAP_SHAREDперед вызовомfork. Стандарт Posix.1 гарантирует в этом случае, что все отображения памяти, установленные родительским процессом, будут унаследованы дочерним. Более того, изменения в содержимом файла, вносимые родительским процессом, будут видны дочернему, и наоборот. Эту схему мы вскоре продемонстрируем в действии.
Для отключения отображения файла в адресное пространство процесса используется вызов munmap:
#include <sys/mman.h>
int munmap (void *addr, size_t len);
/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */
Аргумент addrдолжен содержать адрес, возвращенныйmmap, аlen– длину области отображения. После вызоваmunmapлюбые попытки обратиться к этой области памяти приведут к отправке процессу сигналаSIGSEGV(предполагается, что эта область памяти не будет снова отображена вызовомmmap).
Если область была отображена с флагом MAP_PRIVATE, все внесенные за время работы процесса изменения сбрасываются.
В изображенной на рис. 19.3схеме ядро обеспечивает синхронизацию содержимого файла, отображенного в память, с самой памятью при помощи алгоритма работы с виртуальной памятью (если сегмент был отображен с флагомMAP_SHARED). Если мы изменяем содержимое ячейки памяти, в которую отображен файл, через некоторое время содержимое файла будет соответствующим образом изменено ядром. Однако в некоторых случаях нам нужно, чтобы содержимое файла всегда было в соответствии с содержимым памяти. Тогда для осуществления моментальной синхронизации мы вызываемmsync:
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
/* возвращает 0 в случае успешного завершения, -1 – в случае ошибки */
Аргумент flagsпредставляет собой комбинацию констант из табл.19.3.
Таблица 19.3
Значения аргумента flagsдля функцииmsync
Константа |
Описание |
MS_ASYNC |
Осуществлять асинхронную запись |
MS_SYNC |
Осуществлять синхронную запись |
MS_INVALIDATE |
Сбросить кэш |
Из двух констант MS_ASYNCиMS_SYNCуказать нужно одну и только одну. Отличие между ними в том, что возврат из функции при указании флагаMS_ASYNCпроисходит сразу же, как только данные для записи будут помещены в очередь ядром, а при указании флагаMS_SYNCвозврат происходит только после завершения операций записи. Если указан и флагMS_INVALIDATE, все копии файла, содержимое которых не совпадает с его текущим содержимым, считаются устаревшими. Последующие обращения к этим копиям приведут к считыванию данных из файла.
Почему вообще используется отображение в память? До сих пор мы всегда говорили об отображении в память содержимого файла, который сначала открывается вызовомopen, а затем отображается вызовомmmap. Удобство состоит в том, что все операции ввода-вывода осуществляются ядром и скрыты от программиста, а он просто пишет код, считывающий и записывающий данные в некоторую область памяти. Ему не приходится вызыватьread,writeилиlseek. Часто это заметно упрощает код.
Следует, однако, иметь в виду, что не все файлы могут быть отображены в память. Попытка отобразить дескриптор, указывающий на терминал или гнездо, приведет к возвращению ошибки при вызове mmap. К дескрипторам этих типов доступ осуществляется только с помощьюreadиwrite(и аналогичных вызовов).
Другой целью использования mmapможет являться разделение памяти между неродственными процессами. В этом случае содержимое файла становится начальным содержимым разделяемой памяти и любые изменения, вносимые в нее процессами, копируются обратно в файл (что дает этому виду IPC живучесть файловой системы). Предполагается, что при вызовеmmapуказывается флагMAP_SHARED, необходимый для разделения памяти между процессами.