【问题标题】:Automatically delete files created by a library when it is killed库被杀死时自动删除由库创建的文件
【发布时间】:2018-09-04 15:41:11
【问题描述】:

我有一个必须创建临时文件的 Linux 动态库。这些文件必须有一个文件名——它们不能被创建并立即取消链接。我也无法拦截像SIGINTSIGKILL 这样的信号,因为这是一个被其他程序使用的库。

当创建文件的进程被杀死时,是否有一种理智的方法可以自动删除文件?

说明:

  1. 这些确实是我的限制。当我刚刚在问题中说我不能unlink()时,请不要回答说“你可以unlink()”。
  2. 我意识到这需要操作系统支持 - 很明显,当我的程序被杀死时,它就无法运行任何代码本身来删除文件。但可能有一些方法可以标记文件,以便操作系统删除它们。

例如,Windows 有一个"delete on close" 选项,这意味着当您的程序被杀死时,它所打开的所有文件都会被关闭并自动删除(我认为;我没有尝试过)。如果在某个地方存在这样的功能,那么理论上在 Linux 上这样的事情显然是可能的。我只想知道有没有。

【问题讨论】:

  • 请显示一些代码...作为minimal reproducible example
  • 这个问题不需要代码。
  • 这是你的意见。
  • 为什么他们必须保留文件名?
  • @BasileStarynkevitch,诸如“为什么这段代码不起作用?”之类的问题。必须提供 MCVE。这个问题不符合这种模式。 LLVM 无关紧要,因为与任何只接受文件名的程序交互都会遇到同样的问题。

标签: c++ linux temporary-files


【解决方案1】:

创建一个文件,然后将/proc/self/fd/X 传递给 LLVM,其中 X 是您的文件描述符。您现在可以取消链接(正如 Basile 建议的那样),

由于/proc/self 仅在您的程序关闭时才会消失,因此名称和文件的寿命足够长。

【讨论】:

  • 我认为/proc/self/fd/X应该在之前打开取消链接
  • 这几乎可以工作(出于我的目的),但不幸的是我的程序有很多临时文件(如 5000),ulimit -n 在大多数系统上默认为 1024。愚蠢的Linux。可能不得不接受我的回答。 :-/
  • 文件解链时无关紧要,可以在子进程启动前或启动后进行。重要的是,只要子进程可能想要使用 /proc/<PID>/fd/<FD> 路径,您的进程就会保持文件打开,因为关闭它会删除该目录条目 AFAIK。顺便说一句:那真的可以使用self 作为路径中的组件吗?一个进程的自身与另一个进程不同。
  • @UlrichEckhardt:这个问题专门讨论了一个在进程中执行的库。所以是的,在这种情况下/proc/self 有效。
  • 是的。我的印象是 LLVM 是由图书馆在一个单独的进程中启动的,但鉴于目前的信息,情况并非如此。
【解决方案2】:

虽然这不是特别明智,但 Linux 允许您通过 /proc/$pid/fd/$number 传递已删除文件的名称。

【讨论】:

  • 第一个实际上并没有忽略问题的答案,谢谢!
  • 如果您通过此路径打开了文件的句柄,则不会删除文件。当不再存在指向它们的链接(包括这个!)时,文件将被删除。
【解决方案3】:

我有一个必须创建临时文件的 Linux 动态库。

您可以使用atexit(3) 注册一个处理程序,该处理程序将在exit(3) 时间(或main 的正常终止)删除所有这些临时文件。当然,这不适用于信号。

您可以在某些tmpfs 文件系统中创建这些文件。然后它们将在关机时被删除。

如果您遵循有关这些文件的一些命名约定,您还可以使用一些清理脚本(由一些 crontab 条目触发)发布您的库。

当创建文件的进程被杀死时,是否有一种理智的方法可以自动删除文件?

一般不(并且不可能有一个具有 POSIX 文件语义的)。您可以编写一个清理程序(可能使用inotify(7) 设施)以从外部运行(例如,作为crontab 作业,或作为某个守护进程)。

您也可以在创建后unlink(2) 每个此类临时文件(使用opencreat)并为其保留文件描述符。然后,当进程终止时,或者当它close-s 那个文件描述符时,文件资源被回收。 tmpfile(3) 使用了这个技巧。

顺便说一句,如果您使用 LLVM 作为 JIT 转换器,您可以考虑使用 libgccjit。它能够在没有任何输入文件的情况下生成代码。

此类临时文件无法自动删除,因为某些 其他 进程可以在任意时刻(按其名称)打开它们。这就是为什么 Linux 不能有“关闭时删除”的原因(相反,据传 Windows 只允许单个进程写入给定文件)。

但可能有一些方法可以标记文件,以便操作系统删除它们。

不,不在 Linux 或 POSIX 上。该功能应由应用程序代码提供。

【讨论】:

  • 是的,可悲的是,这只适用于正常程序终止,除了 RAII 对我没有任何帮助。
  • 我不能unlink()。我说我需要保留文件名。并且将清理脚本添加到 crontab 对图书馆来说并不是一个明智的解决方案。
  • 那你有什么建议呢?我试图解释你的期望是不合理的(你想要达到的目标是不可能的)
  • 我希望得到一个答案,要么实际上回答了这个问题,要么给出了一些不可能的权威理由。如果我的约束不是真正的约束,那么我就不会把它们放在问题中!
【解决方案4】:

另一个可能的解决方案是fork() 一个子进程。然后通过某种机制将所有临时文件名发送到此进程。

子进程可以像这样注册以知道其父进程何时被杀死:

#include <sys/prctl.h>
int ret;
ret = prctl (PR_SET_PDEATHSIG, SIGUSR1);
if (ret)
        perror ("prctl");

然后当父母被杀死时它会收到SIGUSR1。此时就可以正常删除文件了。

【讨论】:

    【解决方案5】:

    不,在使用您的库的程序未运行后,您不能删除这些,因为使用它的程序不再运行。

    相反,您可能应该这样做

    • 在库的正常运行中检查过时/过大/剩余的临时文件(下次运行时清理)
    • 创建一个单独的程序来为您管理这些(定期清理)

    这感觉像是一个相当普遍的问题(我当然有过),但它源于对您的程序可能发生的事情的误解。 SIGKILL 将在您的程序可以处理的范围之外立即终止它,并且不会运行任何进一步的操作。 (一些特殊的可以继续运行)

    正如this post on the subject 所说的那样

    SIGKILL 从您正在运行的进程中拉出地毯,立即终止它。

    【讨论】:

    • 请注意,这并不明显。在 Windows 上,您可以在程序停止运行时删除文件,即使是从库中。缺少此功能的是 Linux。
    • 也许在正常终止期间,但总有你无法控制的状态,例如无法以这种方式处理的断电。
    • 很有可能它仍然可以工作; Windows 更喜欢将这些文件保存在缓存中,因为它知道它们不是持久的。 NTFS 事务日志是第二道防线。
    猜你喜欢
    • 2017-06-30
    • 2010-09-28
    • 1970-01-01
    • 2018-03-27
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-05
    相关资源
    最近更新 更多