【问题标题】:How to create temporary files on linux that will automatically clean up after themselves no matter what?如何在linux上创建无论如何都会自动清理的临时文件?
【发布时间】:2026-02-06 19:55:01
【问题描述】:

我想在 linux 上创建一个临时文件,同时确保该文件在我的程序终止后会消失,即使它被杀死或有人在错误的时刻执行了硬重启。 tmpfile() 会为我处理这一切吗?

【问题讨论】:

  • @JarrodRoberson 我将重新添加 [race-condition] 标签 - 这是关于 open()unlink() 之间的时间窗口。
  • @JarrodRoberson:呃,你不是在说死锁吗?我对“竞争条件”的定义类似于“有一些并行过程,并且取决于它们在竞争中的速度,会发生不同的事情”。让我们看一下英文*是怎么说的:“竞态条件或竞态危害是电子系统或过程中的一个缺陷,该过程的输出或结果出乎意料地严重依赖于其他事件的顺序或时间。”
  • “当程序由于意外的事件排序导致对同一资源的争用而无法按预期运行时,就会出现竞争条件。” 我假设从您的 cmets 来看,您特别关注的是 dead-lock,这是尝试修复竞争条件(共享资源争用)的结果。目前尚不清楚您的担忧是什么,如果您的应用程序真的那么脆弱,那么在调用unlink() 之前调用tmpfile() 并让程序异常退出是您最不用担心的。

标签: linux temporary-files


【解决方案1】:

您似乎全神贯注于文件可能会因为某些竞态条件而被遗忘的想法,我没有看到解释为什么这是一个问题。

“当程序由于意外的事件顺序导致对同一资源的争用而无法按预期工作时,就会出现竞争条件。”

我假设您的 cmets 对其他答案的关注特别是 死锁,这是尝试修复竞争条件(共享资源争用)的结果。目前尚不清楚您的担忧是什么,如果您的应用程序真的那么脆弱,那么调用 tmpfile() 并在该函数调用 unlink() 之前让程序异常退出是您最不担心的问题。

鉴于没有提及并发、线程或其他进程共享此文件描述符到此临时文件,我仍然看不到 竞态条件 的可能性,也许是这个概念不完整的逻辑事务,但可以检测和清理。

绝对确保清除所有分配的文件系统资源的正确方法是仅在应用程序的退出时,也应在启动-向上。我所有的服务器代码,确保在它启动并使其自身可用之前之前的运行中清除所有内容。

将您的临时文件放在/tmp 的子目录中,确保您的应用程序在启动和正常关闭时清除此子目录。您可以使用 shell 脚本包装您的应用程序启动,该脚本会根据 PID 的存在检测异常 (kill -9) 关闭,并且还会清理活动。

【讨论】:

  • 如果我的程序可能有多个实例,那么在启动时清理就不是那么容易了,对吧?此外,IMO,您可以说杀手进程和临时文件创建之间的“竞赛”。
  • "multiple instances" 是一种并发形式,您的问题中根本没有提到。如果这是一个问题,您需要编辑您的问题并提供所有 相关 问题,现在从您的扩展 cmets 那里得到所有答案,该问题的措辞并不完整。
  • 好吧,我可以添加“多个实例”,是的。但我也可以添加“不是系统上唯一的程序”、“不一定以 root 身份运行”等等——这些事情不都是正常的吗?
  • 没有人能读懂你的想法,你所做的假设是什么,你认为正常假设是主观的。我的假设是由应用程序创建的临时文件有点特定于该应用程序的该实例和私有实现细节,其他任何东西都是泄漏的抽象和设计缺陷。
【解决方案2】:

如果您不想使用tmpfile(),您可以在创建文件后立即unlink()。在关闭之前,它将保持打开状态和分配状态。

但在硬重启时,可能需要 fsck 来恢复空间。但由于情况总是如此,因此这种方法并没有什么特别的缺点。

【讨论】:

  • 所以即使采用这种方法,如果我的程序在open()unlink() 之间死机这种不太可能的情况发生,那么会有一个空的、无用的文件,对吧?好吧,我想这比程序崩溃时一个大而无用的文件要好得多......
【解决方案3】:

根据 tmpfile() 手册页:

文件在关闭或关闭时会被自动删除 程序终止。

我没有测试过,但它似乎应该做你想要的。

此外:

如果没有设置 TMPDIR,默认位置是 /tmp。

然后,当重新启动时,/tmp 将为空。

【讨论】:

  • 看看glibc/stdio-common/tmpfile.c。据我所知,它首先创建一个文件,然后取消链接。
  • 问题在于你的程序退出不干净。例如如果它出现段错误。 AFAIK 不会发生 exit 中的任何清理。
  • 如果您查看@thejh 提到的代码,您会看到文件随即打开并“删除”(取消链接)。在 UNIX 中,直到所有指向该文件的文件描述符都关闭后,该文件才真正被删除。当进程终止时,所有文件描述符都会自动关闭(AFAIK 原因无关紧要)。所以在进程退出之前不需要执行清理。
【解决方案4】:

编辑:是的

我检查了 tmpfile 源,它确实使用了 glglgl 技巧,并立即解锁了文件。

原文:

我会说不。被杀应该可以工作,但我认为它可能会发生,在硬重启后(例如由于断电)文件仍然存在。但这取决于您的 Linux 发行版和使用的设置。

如果临时文件是在 ramdisk 中创建的,它就消失了(那里有 unix 发行版,例如使用基于 ram 的 tmpfs 临时文件)。

或者,如果您使用的环境对 tmp 有特定策略,它也可能消失(可能不是即时的,但通常有策略,例如删除 /tmp 中在一个月内未访问的所有文件),但是它也可以在不强制执行此类规则的标准文件系统上。在这种情况下,文件将保留。

【讨论】:

  • “立即”?如“无竞争条件”或“小时间窗口”?我会说“小时间窗口”...
  • 用“立即”我的意思是,在 tmpfile 的调用中。删除不会通过 atexit(或类似方法)在程序结束时发生。但它不是“即时”的 - “没有竞争条件”。有一个很小的时间窗口在那里打开但没有取消链接。这就是为什么我把我原来的 cmets 留在帖子中的原因,因为它为比赛提供了解决方案(比如 ram 磁盘或 /tmp 策略)。
  • 好吧,清理/tmp 听起来像是一种可行的解决方法……尽管在服务器上,仅在启动时执行它可能是个坏主意。我想一个 cronjob 应该为我的程序创建的东西做它,只需删除所有未打开的文件......但它仍然感觉很糟糕。
  • @thejh:大多数发行版已经有了这样的系统。 Afaik Ubuntu 在启动时检查,RedHat/Fedora/CentOs 每天都有一个 cronjob 检查它。在那里你应该检查你得到了哪个发行版以及它是如何设置的。
【解决方案5】:

通常的做法是设置一个信号处理程序,以便在程序中断时进行清理。这将无法处理 kill -9 或物理重启,这是无法捕获的。在/tmp 中创建临时文件,通常在系统启动时将其清除。剩下的就是教人们在不需要时不要使用kill -9,但这似乎是一场艰苦的战斗。

【讨论】:

  • 嗯...有时您只需要kill -9 一些东西。好吧,我猜你对/tmp 的看法是对的——我真的应该不时擦除它(哎呀,我在那个文件夹中有 2011 年的文件)。但是,我不喜欢没有干净的方法可以做到这一点的想法......
【解决方案6】:

在 linux 中,mktemp 命令有效。

【讨论】:

  • 我假设原始问题的上下文是 C/C++ 代码,tmpfile(3) 是 c 库中的一个函数。 mktemp 是我操作系统上的一个独立程序,由 GNU coreutils 提供。此外,mktemp 不会自动清理临时文件。
最近更新 更多