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