程序终止时保证文件删除(C / C ++)

时间:2009-01-22 23:53:59

标签: c++ c file termination unlink

Win32的CreateFileFILE_FLAG_DELETE_ON_CLOSE,但我在Linux上。

我想打开一个临时文件,在程序终止时将永远删除该文件。我可以理解,在程序崩溃的情况下,保证这一点可能不切实际,但在任何其他情况下我都希望它可以工作。

我知道RAII。我知道信号。我知道atexit(3)。我知道我可以打开文件并立即删除它,文件将保持可访问状态,直到文件描述符关闭(甚至处理崩溃)。这些似乎都不是一个完整而直接的解决方案:

  1. RAII:去过那里,完成了:我有一个析构函数删除文件的对象,但如果程序被一个信号终止,则不会调用析构函数。
  2. 信号:我正在编写一个低级库,这使得注册信号处理程序变得棘手。例如,如果应用程序本身使用信号怎么办?我不想踩任何脚趾。我可能会考虑巧妙地使用sigaction(2)来应对......但是还没有充分考虑这种可能性。
  3. atexit(3):显然没用,因为它在异常终止期间没有被调用(例如通过信号)。
  4. preemptive unlink(2):这是非常好的,除了我需要文件在文件系统中保持可见(否则系统更难监控/排除故障)。
  5. 你会在这做什么?

    进一步说明

    我在原帖中省略了一个细节,我现在意识到应该包括在内。在这种情况下,“文件”不是严格意义上的普通文件,而是POSIX消息队列。我是通过mq_open()创建的。它可以通过mq_close()close()关闭(前者是我系统中后者的别名)。它可以通过mq_unlink()从系统中删除。所有这些使得它类似于常规文件,除了,我无法选择文件所在的目录。这使得当前最流行的答案(将文件置于/tmp)不可行,因为“文件”是由系统在容量非常有限的虚拟文件系统中创建的。 (我已按照/dev/mqueue中的示例将虚拟文件系统挂载到man mq_overview中。

    这也解释了为什么我需要名称保持可见(使立即取消链接方法不可行):“文件”必须在两个或多个进程之间共享。

8 个答案:

答案 0 :(得分:7)

在进程运行时名称仍然可见的要求使得这很难实现。你能重温这个要求吗?

如果没有,那么可能没有一个完美的解决方案。我会考虑将信号处理策略与Kamil Kisiel建议的结合起来。在安装信号处理程序之前,您可以跟踪安装的信号处理程序。如果默认处理程序是SIG_IGN,则通常不会安装自己的处理程序;如果是SIG_DFL,你会记得那个;如果它是其他东西 - 用户定义的信号处理程序 - 你会记住该指针,并安装自己的。当你的处理程序被调用时,你会做你需要做的任何事情,然后调用记住的处理程序,从而链接处理程序。您还将安装atexit()处理程序。您还会记录您执行此操作以及执行此操作的信号。

请注意,信号处理是一种不完美的策略;无法捕获SIGKILL,并且不会调用atexit()处理程序,并且文件将被保留。

David Segond的建议 - 临时文件名守护程序 - 很有趣。对于简单的过程,这就足够了;如果请求临时文件的进程分叉并且期望子进程此后拥有该文件(并退出),那么该守护进程在检测使用它的最后一个进程何时死亡时会出现问题 - 因为它不会自动知道打开它的进程。

答案 1 :(得分:6)

如果您只是制作临时文件,只需在/tmp或其子目录中创建即可。然后,通过atexit(3)或类似操作,尽最大努力将其删除。只要您使用通过mkstemp(3)或类似名称选择的唯一名称,即使由于程序崩溃而无法删除它,您也不会冒险在后续运行或其他此类条件下再次阅读它。

此时,这只是保持/tmp清洁的系统级问题。大多数发行版在启动或关闭时擦除它,或者运行常规cronjob来删除旧文件。

答案 2 :(得分:4)

也许有人建议这一点,但我无法发现它,鉴于您的所有要求,我能想到的最好的方法是将文件名以某种方式传达给父进程,例如启动脚本,这将是如果没有这样做,那么在过程死亡后清理干净。这可能通常被称为监视程序,但随后添加更常见的用例以在某种程度上失败时杀死和/或重启进程。

如果您的父进程也死了,那么你很不幸,但是大多数脚本环境相当健壮并且很少死,除非脚本被破坏,这通常比程序更容易保持正确。

答案 3 :(得分:3)

过去,我已经建立了一个“临时文件管理器”来跟踪临时文件。

可以从经理那里请求一个临时文件名,并注册该名称。

一旦您不再需要临时文件名,您就会通知经理并且文件名未注册。

收到终止信号后,所有已注册的临时文件都被销毁。

临时文件名是基于UUID的,以避免冲突。

答案 4 :(得分:1)

您可以在创建文件后使用进程fork,然后等待子进程关闭,然后父进程可以取消链接该文件并退出。

答案 5 :(得分:1)

我刚刚加入stackoverflow并在此找到你:)

如果您遇到的问题是管理mq文件并防止它们堆积,您实际上不需要保证在终止时删除文件。如果您只想堆积无用的文件,那么保留期刊可能就是您所需要的。打开mq后,在日志文件中添加一个条目,关闭它时的另一个条目,以及初始化库时,检查日志中的不一致性,并采取纠正不一致所需的任何操作。如果您担心在调用mq_open/mq_close时崩溃,您也可以在调用这些函数之前添加日记条目。

答案 6 :(得分:1)

  • 在点目录下有临时文件的簿记目录。
  • 创建临时文件时,首先在簿记目录中创建簿记文件,该目录包含要成为临时文件的路径或UUID。
  • 创建该临时文件。
  • 删除临时文件后,删除簿记文件。
  • 当程序启动时,扫描簿记目录以查找包含临时文件路径的任何文件,如果找到则尝试删除它们,删除簿记文件。
  • (如果任何步骤失败,请大声记录。)

我没有办法以任何方式更简单地做到这一点。这是任何生产质量计划必须经历的样板;容易+500行。

答案 7 :(得分:0)

真的需要名字保持可见吗?

假设您选择立即取消链接文件。然后:

  •   

    preemptive unlink(2):这是非常好的,除了我需要文件在文件系统中保持可见(否则系统更难监控/故障排除)。

    您仍然可以对已删除的文件进行调试,因为它仍会在/proc/$pid/fd/下显示。只要您了解流程的pid,就可以轻松枚举其打开的文件。

  •   

    名称需要在正常操作期间保持可见,因为它们在程序之间共享。

    您仍然可以通过在Unix域套接字上传递文件描述符来共享进程之间已删除的打开文件。有关详细信息,请参阅Portable way to pass file descriptor between different processes