С помощью команды ipcs -s
можно получить информацию о существующих группах семафоров. Команда ipcrm sem
позволяет удалить заданную группу, например:
% ipcrm sem 5790517
5.3. Отображение файлов в памяти
Благодаря механизму отображаемой памяти процессы получают возможность общаться друг с другом посредством совместно используемого файла. Схематически это можно представить как совместный доступ к именованному сегменту памяти, хотя технически оба механизма реализованы по-разному.
При отображении файла в памяти формируется связь между файлом и памятью процесса. ОС Linux разбивает файл на страничные блоки и копирует их в страницы виртуальной памяти, чтобы они стали доступны в адресном пространстве процесса. Таким образом, процесс сможет обращаться к содержимому файла как к обычной памяти. При записи данных в соответствующую область памяти содержимое файла будет меняться. Это ускоряет доступ к файлам.
Отображаемую память можно представить как буфер, в который загружается все содержимое файла. Если данные, находящиеся в буфере, модифицируются, они записываются обратно в файл. Операции чтения и записи ОС Linux обрабатывает самостоятельно.
Файлы, отображаемые в памяти, можно использовать не только для организации взаимодействия процессов. О других применениях таких файлов пойдет речь в разделе 5.3.5. "Другие применения функции mmap()".
5.3.1. Отображение в памяти обычного файла
Для отображения обычного файла в памяти процесса предназначена функция mmap()
. Ее первым аргументом является адрес, который будет соответствовать началу отображаемого файла в адресном пространстве процесса. Если задать значение NULL
, ОС Linux выберет первый доступный адрес. Второй аргумент — это длина отображаемой области в байтах. Третий аргумент задает степень защиты диапазона отображаемых адресов. Он может содержать объединение битовых констант PROT_READ
, PROT_WRITE
и PROT_EXEC
, соответствующих разрешению на чтение, запись и выполнение соответственно. Четвертый аргумент содержит дополнительные флаги. Пятый аргумент — это дескриптор открытого файла. В последнем аргументе задается смещение от начала файла, с которого начинается отображаемая область. Можно перенести в память весь файл или только часть его, должным образом корректируя начальное смещение и длину отображаемой области.
Ниже перечислены дополнительные флаги, задаваемые в четвертом аргументе.
■ MAP_FIXED
. При наличии этого флага ОС Linux использует значение первого аргумента как точный адрес размещения отображаемого файла. Этот адрес должен соответствовать началу страницы.
■ MAP_PRIVATE
. Изменения, вносимые в отображаемую память, записываются не в присоединенный файл, а в частную копию файла, принадлежащую процессу. Другие процессы не узнают об этих изменениях. Данный режим не совместим с режимом MAP_SHARED
.
■ MAP_SHARED
. Изменения, вносимые в отображаемую память, немедленно фиксируются в файле, минуя буфер. Этот режим используется при организации взаимодействия процессов и не совместим с режимом MAP_PRIVATE
.
При успешном завершении функция возвращает указатель на начало области памяти. В противном случае возвращается флаг MAP_FAILED
.
По окончании работы с отображаемым файлом его необходимо освободить с помощью функции munmap()
. Ей передается начальный адрес и длина отображаемой области. ОС Linux автоматически освобождает отображаемые области при завершении процесса.
В этом разделе рассматриваются две программы, в которых иллюстрируются чтение и запись файлов, отображаемых в памяти. Первая программа (листинг 5.5) генерирует случайное число и записывает его в отображаемый файл. Вторая программа (листинг 5.6) читает число из файла, выводит его на экран, а затем умножает на 2 и записывает обратно в файл. Обе программы принимают имя файла из командной строки.
Листинг 5.5. ( mmap-write.c ) Запись случайного числа в файл, отображаемый в памяти
#include
#include
#include
#include
#include
#include
#include
#define FILE_LENGTH 0x100
/* получение случайного числа в диапазоне [low,high]. */
int random_range(unsigned const low, unsigned const high) {
unsigned const range = high - low + 1;
return
low + (int)(((double)range) * rand() / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[]) {
Читать дальше