Да, у вас есть несколько вариантов, хотя POSIX поддерживает только первое приведенное ниже предложение.Остальные зависят от ОС и могут не переноситься во все системы POSIX, хотя я верю, что они работают во всех системах POSIXy.
Вы можете использовать именованныйpipe (FIFO) и иметь вспомогательный поток, считываемый из него одновременно с функцией записи.
Поскольку самого файла нет, служебные данные - это просто системные вызовы (запись и чтение);в основном просто накладные расходы на межпроцессное взаимодействие, не о чем беспокоиться.Чтобы сэкономить ресурсы, создайте вспомогательный поток с небольшим стеком (используя pthread_attr_
и т. Д.), Так как размер стека по умолчанию имеет тенденцию быть огромным (порядка нескольких мегабайт; 2*PTHREAD_STACK_SIZE
должно быть достаточно для вспомогательных потоков.)
Вы должны убедиться, что именованный канал находится в безопасном каталоге, доступном, например, только пользователю, выполняющему процесс.
Во многих системах POSIXy,Вы можете создать трубу или пару сокетов и получить к ней доступ через /dev/fd/N
, где N
- номер дескриптора в десятичном виде.(В Linux /proc/self/fd/N
также работает.) Это не обязательно для POSIX, поэтому может быть доступно не во всех системах, но большинство его поддерживают.
Таким образом, фактического файла как такового не существует,и функция пишет в канал или сокет.Если данные, записанные функцией, не превышают PIPE_BUF
байтов, вы можете просто прочитать данные из канала впоследствии;в противном случае вам необходимо создать вспомогательный поток для чтения из канала или сокета одновременно с функцией, иначе запись будет блокирована.
В этом случае также минимальные накладные расходы.
В системах POSIXy на основе ELF (в основном, во всех) вы можете вставлять системные вызовы open()
, write()
и close()
или функции библиотеки C.
(В Linux есть два основных подхода, один с использованием компоновщика --wrap
, а другой с dlsym()
. Оба прекрасно работают в этом конкретном случае. Эта способность вставлять функции основана на том, как исполняются двоичные файлы ELF.связывается во время выполнения и не имеет прямого отношения к POSIX.)
Сначала вы настраиваете вставляющие функции, так что open()
определяет, соответствует ли имя файла вашему специальному файлу "в памяти", и возвращаетвыделенный номер дескриптора для него.(Вам также может понадобиться вставить другие функции, такие как ftruncate()
или lseek()
, в зависимости от того, что функция на самом деле делает; в Linux вы можете запустить двоичный файл под ptrace
, чтобы проверить, какие системные вызовы он фактически использует.)
Когда write()
вызывается с выделенным номером дескриптора, вы просто memcpy()
записываете его в буфер памяти.Вам потребуется использовать глобальные переменные для описания выделенного размера, используемого размера и указателя на буфер памяти, и, возможно, быть готовым изменить размер / увеличить буфер при необходимости.
Когда вызывается close()
с выделенным номером дескриптора вы знаете, что буфер памяти заполнен, а содержимое готово к обработке.
Вы можете использовать временный файл в файловой системе RAM.В то время как данные технически записываются в файл и считываются из него, в операциях используется только ОЗУ.
Вы должны организовать путь по умолчанию к нему, который будет установлен во время компиляции, и чтобы отдельные пользователи могличтобы переопределить это для своих личных нужд, например, через переменную окружения (YOURAPP_TMPDIR
?).
Приложению не нужно пытаться искать файловую систему на основе ОЗУ: выбор такой:и должно быть, до пользователя.Приложение не должно заботиться даже о том, какая файловая система используется, и должно просто использовать указанный каталог.