Гарантированное удаление файла после завершения программы (C/С++)
Win32 CreateFile
имеет FILE_FLAG_DELETE_ON_CLOSE
, но я нахожусь в Linux.
Я хочу открыть временный файл, который всегда будет удален после завершения программы. Я мог понять, что в случае сбоя программы может быть нецелесообразно гарантировать это, но в любом другом случае я бы хотел, чтобы он работал.
Я знаю об RAII. Я знаю о сигналах. Я знаю о atexit(3)
. Я знаю, что могу открыть файл и немедленно удалить его, и файл останется доступным до тех пор, пока дескриптор файла не будет закрыт (что даже приведет к сбою). Ни одно из них не похоже на полное и простое решение:
- RAII: был там, сделал это: у меня есть объект, деструктор которого удаляет файл, но деструктор не вызывается, если программа завершается сигналом.
Сигналы
- : Я пишу низкоуровневую библиотеку, которая делает запись обработчика сигнала сложным предложением. Например, что, если приложение использует сигналы самостоятельно? Я не хочу наступать на все пальцы. Я мог бы подумать о некотором умном использовании
sigaction(2)
, чтобы справиться... но пока не задумался над этой возможностью.
-
atexit(3)
: кажется бесполезным, поскольку он не вызывается во время аномального завершения (например, через сигнал).
- preemptive
unlink(2)
: это довольно хорошо, за исключением того, что мне нужно, чтобы файл оставался видимым в файловой системе (в противном случае системе сложнее отслеживать/устранять неполадки).
Что бы вы сделали здесь?
Дальнейшее объяснение
Я удалил одну деталь в своем оригинальном посте, и теперь я понял, что должен был включить. "Файл" в этом случае не является строго нормальным файлом, а скорее представляет собой очередь сообщений POSIX. Я создаю его через mq_open()
. Его можно закрыть с помощью mq_close()
или close()
(первый - это псевдоним для последней в моей системе). Его можно удалить из системы через mq_unlink()
. Все это делает его аналогичным регулярному файлу, за исключением того, что я не могу выбрать каталог, в котором находится файл. Это делает текущий самый популярный ответ (размещение файла в /tmp
) неработоспособным, потому что "файл" создается системой в виртуальной файловой системе с очень ограниченной емкостью. (Я установил виртуальную файловую систему в /dev/mqueue
, следуя примеру в man mq_overview
).
Это также объясняет, почему мне нужно, чтобы имя оставалось видимым (что делает немедленный подход незаменимым): "файл" должен быть разделен между двумя или более процессами.
Ответы
Ответ 1
Требование, чтобы имя оставалось видимым во время выполнения процесса, затрудняет достижение этого. Можете ли вы пересмотреть это требование?
Если нет, то, вероятно, это не идеальное решение. Я хотел бы рассмотреть возможность комбинирования стратегии обработки сигналов с тем, что предлагает Камиль Кисиэль. Вы можете отслеживать обработчики сигналов, установленные перед установкой обработчиков сигналов. Если обработчик по умолчанию - SIG_IGN, вы обычно не будете устанавливать свой собственный обработчик; если это SIG_DFL, вы бы это вспомнили; если это что-то другое - пользовательский обработчик сигналов - вы бы запомнили этот указатель и установили свой собственный. Когда ваш обработчик был вызван, вы сделаете все, что вам нужно, а затем вызовите запоминающегося обработчика, таким образом, привяжите обработчики. Вы также установили обработчик atexit(). Вы также будете документировать, что вы это делаете, и сигналы, для которых вы это делаете.
Обратите внимание, что обработка сигналов - это несовершенная стратегия; SIGKILL нельзя поймать, и обработчик atexit() не будет вызван, и файл будет оставлен.
Предложение David Segond - временный демона имени файла - интересно. Для простых процессов это достаточно; если процесс, запрашивающий временные файловые вилки, и ожидает, что дочерний элемент будет потом иметь файл (и выходит), тогда у демона возникнет проблема с обнаружением, когда последний процесс, использующий его, умирает, потому что он не знает автоматически процессы, которые его открывают.
Ответ 2
Если вы просто создаете временный файл, просто создайте его в /tmp
или в его подкаталоге. Затем приложите все усилия, чтобы удалить его, когда закончите с помощью atexit(3)
или аналогичного. Пока вы используете уникальные имена, выбранные через mkstemp(3)
или подобные, даже если они не могут быть удалены из-за сбоя программы, вы не рискуете прочитать его снова при последующих прогонах или других таких условиях.
В этот момент это всего лишь системная проблема сохранения /tmp
clean. Большинство дистрибутивов стирают его при загрузке или завершении работы или запускают обычный cronjob для удаления старых файлов.
Ответ 3
Возможно, кто-то предложил это уже, но я не могу это определить, учитывая все ваши требования, лучшее, что я могу придумать, - это как-то передать имя файла родительскому процессу, например start- script, который будет очищаться после завершения процесса, если бы он этого не сделал. Это, пожалуй, главным образом известно как сторожевой таймер, но затем с более распространенным случаем использования, добавленным для того, чтобы убить и/или перезапустить процесс, когда он как-то потерпит неудачу.
Если ваш родительский процесс также умирает, вам в значительной степени не повезло, но большинство сред script довольно устойчивы и редко умирают, если только script не работает, что часто бывает легче поддерживать корректно, чем программа.
Ответ 4
В прошлом я создал "временный файловый менеджер", который отслеживал временные файлы.
Можно запросить временное имя файла у менеджера, и это имя было зарегистрировано.
Как только вам не понадобится имя временного файла, вы сообщаете менеджеру, и имя файла не зарегистрировано.
После получения сигнала завершения все зарегистрированные временные файлы были уничтожены.
Временные имена файлов были основаны на UUID, чтобы избежать столкновений.
Ответ 5
Я только что присоединился к stackoverflow и нашел вас здесь:)
Если вам сложно управлять файлами mq и не создавать их нагромождения, вам действительно не нужно гарантировать удаление файла после его завершения. Если вы просто хотите, чтобы ненужные файлы были нагромождены, вам может понадобиться хранить журнал. Добавьте запись в файл журнала после открытия mq, другую запись, когда она закрыта, и когда ваша библиотека инициализирована, проверьте наличие несогласованности в журнале и выполните любые действия, необходимые для исправления несогласованности. Если вы беспокоитесь о сбое при вызове mq_open/mq_close
, вы также можете добавить запись журнала непосредственно перед вызовом этих функций.
Ответ 6
У вас может быть вилка процесса после создания файла, а затем подождите, пока дочерний элемент закроется, а затем родительский может отменить связь с файлом и выйти.
Ответ 7
Вам действительно нужно, чтобы имя оставалось видимым?
Предположим, вы берете опцию немедленного открепления файла. Тогда:
-
preemptive unlink (2): это довольно хорошо, за исключением того, что мне нужно, чтобы файл оставался видимым в файловой системе (в противном случае системе сложнее отслеживать/устранять неполадки).
Вы по-прежнему можете отлаживать удаленный файл, поскольку он все равно будет отображаться под /proc/$pid/fd/
. До тех пор, пока вы знаете pids ваших процессов, перечисление их открытых файлов должно быть легким.
-
имена должны оставаться видимыми во время нормальной работы, поскольку они распределяются между программами.
Вы по-прежнему можете совместно использовать удаленный открытый файл между процессами, передавая файловый дескриптор через сокеты домена Unix. См. Портативный способ передачи файлового дескриптора между различными процессами для получения дополнительной информации.
Ответ 8
- У вас есть справочник по хранению временных файлов в вашем dot-каталоге.
- При создании временного файла сначала создайте файл учета в каталоге учета, содержащий путь или UUID, в ваш временный файл.
- Создайте этот временный файл.
- Когда temp файл удален, а затем удалите файл учета.
- Когда программа запускается, отсканируйте каталог бухгалтерского учета для любых файлов, содержащих пути к временным файлам, и попробуйте удалить их, если они найдены, они удаляют файлы бухгалтерского учета.
- (Лог шумит, если какой-либо шаг не работает.)
Я не вижу способов сделать это проще. Это шаблон, который должна пройти любая программа качества продукции; +500 линий легко.