Гарантированное удаление файлов при завершении программы (C/C++)

StackOverflow https://stackoverflow.com/questions/471344

Вопрос

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

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

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

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

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

Дальнейшее объяснение

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top