Использование mmap над файлом - PullRequest
4 голосов
/ 13 апреля 2009

Я пытаюсь разрешить двум разным процессам взаимодействовать, используя отображение памяти в одном и том же файле. Однако у меня есть некоторые проблемы с этим. У меня есть ощущение, что это связано с тем, как я использую вызов open () и передаю свой файловый дескриптор в mmap.

Вот мой код, видите ли вы что-то не так с ним?

Код объекта 1:

 16     FILE* temp = fopen(theSharedFileName, "w");
 17     fseek(temp, fileSize-1, SEEK_SET);
 18     fprintf(temp, "0"); // make the file a certain size
 19     fseek(temp, 0, SEEK_CUR);
 20 
 21     int sharedFileName = fileno(temp);
 ...
 31     sharedArea = (MyStruct*)mmap(0, fileSize,
 32         PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, sharedFileName, 0);

Я использую режим файла "w", поскольку объект 1 будет создан только один раз, и я хочу, чтобы он сбрасывал все ранее существующие данные.

Код объекта 2:

 130     FILE* tempFile = fopen(sharedFileName, "a");
 131     int theFile = fileno(tempFile);
 ...
 135     sharedArea = (MyStruct*)mmap(NULL, fileSize,
 136         PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, theFile, 0);

Ответы [ 3 ]

24 голосов
/ 13 апреля 2009

Несколько вопросов:

  1. Избегайте смешивания высокоуровневых операций ввода-вывода (fopen (), fseek ()) и некоторых низкоуровневых операций, таких как mmap (). Хотя вы можете получить низкоуровневый файловый дескриптор, используя fileno (), это все равно что пойти по тому же самому длинному маршруту. Кроме того, простое использование mmap () нарушает совместимость за пределами BSD и POSIX, поэтому вы ничего не получите, используя стандартные функции ввода-вывода C. Просто используйте open () и lseek () напрямую.
  2. Нет смысла использовать потоковый ввод-вывод (fprintf ()) в том же файле, который вы отображаете в памяти. Когда вы отображаете файл в память, вы неявно сообщаете системе, что собираетесь использовать его как данные с произвольным доступом (прямая индексация). fprintf () предназначен для вывода потока, обычно вы используете его для последовательного доступа. На самом деле, хотя это и возможно, необычно видеть fprintf () и fseek () в одном и том же дескрипторе (это даже не переносимо, но из-за предыдущего пункта я не рассматриваю переносимость).
  3. Защита должна соответствовать защите открытого файла. Поскольку вы передаете "w" в fopen () и PROT_READ | PROT_WRITE | PROT_EXEC в mmap (), вы нарушаете это ограничение. Это также подчеркивает, почему вы не должны смешивать высокоуровневый ввод-вывод с отображением памяти: как вы гарантируете, что fopen(...,"w") откроет файл с правильными флагами? Предполагается, что это «детали реализации» для библиотеки C. Если вы хотите отобразить в памяти файл с разрешениями на чтение и запись, вы должны использовать низкоуровневый open(theSharedFileName, O_RDWR), чтобы открыть файл.
  4. Не использовать PROT_WRITE и PROT_EXEC вместе. Это не портативный и , это угроза безопасности. Подробнее о W ^ X и защите исполняемого пространства .
2 голосов
/ 13 апреля 2009

Если вы можете использовать C ++ и такие библиотеки, как ACE или Boost , которые защищают вас от низкоуровневых деталей и обеспечивают более простую абстракцию для IPC .

1 голос
/ 13 апреля 2009

Как уже говорили другие, не используйте fopen () и друзей для этого.

Часть проблемы, с которой вы столкнулись, может быть связана с тем фактом, что fprintf () может иметь потоковые буферы, поэтому он может фактически не изменять файл и, следовательно, быть видимым для другого процесса, когда ожидается. Вы можете добавить fflush (), но read () и write () не выполняют буферизацию на уровне приложения, поэтому они более подходят.

...