Гарантированное удаление файла после завершения программы (C / C ++) - PullRequest
19 голосов
/ 23 января 2009

Win32 CreateFile имеет FILE_FLAG_DELETE_ON_CLOSE, но я в Linux.

Я хочу открыть временный файл, который всегда будет удален после завершения программы. Я мог понять, что в случае сбоя программы это может быть непрактично, но в любом другом случае мне бы хотелось, чтобы это работало.

Я знаю о РАИИ. Я знаю о сигналах. Я знаю о atexit(3). Я знаю, что могу открыть файл и удалить его немедленно, и файл останется доступным, пока дескриптор файла не будет закрыт (что даже обрабатывает сбой). Ничто из этого не кажется полным и простым решением:

  1. RAII: был там, сделал это: у меня есть объект, деструктор которого удаляет файл, но деструктор не вызывается, если программа завершается сигналом.
  2. сигналов: я пишу низкоуровневую библиотеку, которая делает регистрацию обработчика сигналов сложным предложением. Например, что если приложение само использует сигналы? Я не хочу наступать ни на какие пальцы. Я мог бы подумать о некотором умном использовании sigaction(2), чтобы справиться ... но я еще не достаточно задумался над этой возможностью.
  3. atexit(3): по-видимому, бесполезно, поскольку не вызывается во время аварийного завершения (например, через сигнал).
  4. preemptive unlink(2): это довольно хорошо, за исключением того, что мне нужно, чтобы файл оставался видимым в файловой системе (в противном случае систему сложнее отслеживать / устранять).

Что бы вы здесь делали?

Дополнительные пояснения

Я исключил одну деталь из своего исходного поста, которую теперь понимаю, что должен был включить. «Файл» в данном случае не является строго обычным файлом, а представляет собой очередь сообщений POSIX. Я создаю это через mq_open(). Его можно закрыть с помощью mq_close() или close() (первый - псевдоним последнего в моей системе). Его можно удалить из системы с помощью mq_unlink(). Все это делает его аналогичным обычному файлу , за исключением , в котором я не могу выбрать каталог, в котором находится файл. Это делает текущий самый популярный ответ (помещая файл в /tmp) неработоспособным, потому что «файл» создается системой в виртуальной файловой системе с очень ограниченными возможностями. (Я смонтировал виртуальную файловую систему в /dev/mqueue, следуя примеру в man mq_overview).

Это также объясняет, почему мне нужно, чтобы имя оставалось видимым (делая невозможным использование немедленного разъединения): «файл» должен быть разделен между двумя или более процессами.

Ответы [ 8 ]

7 голосов
/ 23 января 2009

Требование, чтобы имя оставалось видимым во время выполнения процесса, затрудняет достижение этого. Можете ли вы вернуться к этому требованию?

Если нет, то, вероятно, не существует идеального решения. Я хотел бы рассмотреть возможность сочетания стратегии обработки сигналов с тем, что предлагает Камил Кисиэль. Вы можете отслеживать установленные обработчики сигналов, прежде чем устанавливать свои обработчики сигналов. Если обработчиком по умолчанию является SIG_IGN, вы обычно не устанавливаете свой собственный обработчик; если это SIG_DFL, вы бы это запомнили; если это что-то другое - пользовательский обработчик сигнала - вы запомните этот указатель и установите свой собственный. Когда вызывался ваш обработчик, вы делали все, что вам нужно, а затем вызывали запомненный обработчик, таким образом связывая обработчики. Вы также должны установить обработчик atexit (). Вы также должны задокументировать, что вы делаете это, и сигналы, для которых вы делаете это.

Обратите внимание, что обработка сигналов является несовершенной стратегией; SIGKILL не может быть перехвачен, и обработчик atexit () не будет вызван, а файл останется вокруг.

Предложение Дэвида Сегонда - демона временного имени файла - интересно. Для простых процессов этого достаточно; если процесс, запрашивающий временный файл, разветвляется и ожидает, что дочерний файл станет владельцем файла после этого (и завершится), тогда у демона возникнет проблема с обнаружением, когда последний процесс, использующий его, умрет - потому что он не знает автоматически процессы, у которых он открыт.

6 голосов
/ 23 января 2009

Если вы просто создаете временный файл, просто создайте его в /tmp или его подкаталоге. Затем сделайте все возможное, чтобы удалить его, когда это сделано через atexit(3) или подобное. Пока вы используете уникальные имена, выбранные с помощью mkstemp(3) или аналогичные, даже если они не удаляются из-за сбоя программы, вы не рискуете прочитать его снова при последующих запусках или других подобных условиях.

На данный момент это проблема системного уровня /tmp в чистоте. Большинство дистрибутивов стирают его при загрузке или завершении работы, либо запускают обычный cronjob для удаления старых файлов.

4 голосов
/ 23 января 2009

Может быть, кто-то уже предлагал это, но я не могу определить это, учитывая все ваши требования, лучшее, что я могу придумать, это как-то связать имя файла с родительским процессом, таким как start-script, который будет очистить после того, как процесс умирает, если это не удалось сделать. Возможно, это в основном известно как сторожевой таймер, но затем добавляется более распространенный вариант использования для уничтожения и / или перезапуска процесса, когда он каким-то образом завершается неудачей.

Если ваш родительский процесс также умирает, вам в значительной степени не повезло, но большинство сред сценариев довольно устойчивы и редко умирают, если сценарий не сломан, что часто легче исправить, чем программа.

3 голосов
/ 23 января 2009

В прошлом я создавал «временный файловый менеджер», который отслеживал временные файлы.

Можно запросить временное имя файла у менеджера, и это имя было зарегистрировано.

Если вам больше не нужно временное имя файла, вы сообщаете об этом менеджеру, а имя файла не регистрируется.

После получения сигнала завершения все зарегистрированные временные файлы были уничтожены.

Временные имена файлов основаны на UUID, чтобы избежать коллизий.

1 голос
/ 05 августа 2015
  • У вас есть каталог для хранения временных файлов в вашем dot-каталоге.
  • При создании временного файла сначала создайте файл учета в каталоге учета, который содержит путь или UUID к вашему временному файлу.
  • Создайте этот временный файл.
  • Если временный файл удален, удалите файл учета.
  • Когда программа запускается, просмотрите каталог бухгалтерии на наличие файлов, содержащих пути к временным файлам, и попробуйте удалить их, если они найдены, они удаляют файлы бухгалтерии.
  • (Зашумлять, если какой-либо шаг не удался.)

Я не вижу способов сделать это проще. Это образец, который должна пройти любая программа качества продукции; +500 строк легко.

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

Я только что присоединился к stackoverflow и нашел тебя здесь:)

Если ваша проблема заключается в управлении mq-файлами и предотвращении их накопления, вам не нужно гарантировать удаление файла после завершения. Если вы просто хотели, чтобы бесполезные файлы копились, то вам может понадобиться вести журнал. Добавьте запись в файл журнала после открытия mq, другую запись, когда она закрыта, и когда ваша библиотека инициализируется, проверьте наличие несоответствий в журнале и предпримите все необходимые действия для исправления несоответствия. Если вы беспокоитесь о сбое при вызове mq_open/mq_close, вы также можете добавить запись в журнале непосредственно перед вызовом этих функций.

1 голос
/ 23 января 2009

После создания файла вы можете получить ответвление процесса, а затем подождать, пока дочерний объект закроется, а затем родительский узел сможет отсоединить файл и выйти.

0 голосов
/ 14 августа 2012

Вам действительно нужно, чтобы имя оставалось видимым?

Предположим, вы выбрали немедленную отмену удаления файла. Тогда:

  • упреждающий unlink (2): это довольно хорошо, за исключением того, что мне нужно, чтобы файл оставался видимым в файловой системе (в противном случае систему сложнее отслеживать / устранять).

    Вы по-прежнему можете отлаживать удаленный файл, так как он все еще будет виден в /proc/$pid/fd/. Если вы знаете pids своих процессов, перечисление их открытых файлов должно быть простым.

  • имена должны оставаться видимыми во время нормальной работы, поскольку они совместно используются программами.

    Вы все еще можете поделиться удаленным открытым файлом между процессами, передавая дескриптор файла через доменные сокеты Unix. См. Переносимый способ передачи файлового дескриптора между различными процессами для получения дополнительной информации.

...