草庐IT

关于 c : 当一个库被杀死时自动删除它创建的文件

codeneng 2023-03-28 原文

Automatically delete files created by a library when it is killed

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

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

澄清:

  • 这些确实是我的限制。当我刚刚在问题中说我不能 unlink() 时,请不要回答说"你可以 unlink()"。
  • 我意识到这将需要操作系统支持——显然,当我的程序被杀死时,它本身就不能运行任何代码来删除文件。但是可能有一些方法可以标记文件,以便操作系统删除它们。
  • 例如,Windows 有一个"关闭时删除"选项,这意味着当您的程序被杀死时,它所拥有的任何打开的文件都会被关闭并自动删除(我认为;我没有尝试过)。如果在某个地方存在这样的功能,那么理论上在 Linux 上这样的事情显然是可能的。我只想知道有没有。

    • 请显示一些代码......作为一个最小的可重现示例
    • 这个问题不需要代码。
    • 那是你的意见。
    • 为什么他们必须保留文件名?
    • 它们被传递给 LLVM,它只接受文件名形式的输入(有朝一日我们有望解决这个问题,但这是一项艰巨的任务)。
    • LLVM 应在问题中提及(不在评??论中)
    • @BasileStarynkevitch,诸如"为什么这段代码不起作用?"之类的问题必须提供 MCVE。这个问题不符合这个模式。 LLVM 无关紧要,因为与任何只接受文件名的程序的交互都会遇到同样的问题。
    • LLVM 可以从标准输入读取它,不是吗?
    • LLVM 是相关的,因为它接受文件名。
    • LLVM 无法从标准输入中读取,LLVM 本身与问题无关。我不会为此重新架构 LLVM。我已经清楚地解释了问题中的限制。
    • 文件必须有你说的名字?取消链接后尝试 /proc/<pid>/fd/<fd> 。但不能保证在所有情况下都能正常工作。
    • 您还可以让库分叉一个看门狗进程。或者,如果您真的很偏执,两个监视父进程和彼此的看门狗进程。
    • @n.m.:你的意思是之前,不是之后,对吧?
    • @LightnessRacesinOrbit 如果您愿意,您可以在之前执行此操作,但这没有多大意义,因为在取消链接之前,文件仍然可以以其原始名称使用,您可以使用它来代替。
    • @n.m。呃,没关系,我在脑海中混淆了"使用 /proc/.. 路径"和"获取文件的句柄":D


    创建一个文件,然后将 /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 是由图书馆在一个单独的进程中启动的,但鉴于现有的信息,情况并非如此。


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

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


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

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

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

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


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

    相反,您可能应该

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

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

    正如这篇关于这个主题的帖子所说的那样

    SIGKILL pulls the rug out from your running process, terminating it immediately.

    • 请注意,这并不明显。在 Windows 上,您可以在程序停止运行时删除文件,甚至可以从库中删除。它的 Linux 缺少这个特性。
    • 也许在正常终止期间,但总有您无法控制的状态,例如无法以这种方式处理的断电。
    • 很有可能它仍然可以工作。 Windows 更喜欢将这些文件保存在缓存中,因为它知道它们不是持久的。 NTFS 事务日志是第二道防线。


    I have a Linux dynamic library that has to create temporary files.

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

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

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

    Is there a sane way to have the files automatically deleted when the process that created them is killed?

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

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

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

    这样的临时文件不能被自动删除,因为其他一些进程可以打开它们(通过它们的名字)——在任意时刻。这就是为什么 Linux 不能"关闭时删除"(相反,据传 Windows 只允许单个进程写入给定文件)。

    But there may be some way to mark the files so that the OS deletes them.

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

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

    有关关于 c : 当一个库被杀死时自动删除它创建的文件的更多相关文章

    1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    2. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    3. ruby - 其他文件中的 Rake 任务 - 2

      我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

    4. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    5. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

      我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

    6. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    7. ruby-on-rails - Rails 3 中的多个路由文件 - 2

      Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

    8. ruby - 将差异补丁应用于字符串/文件 - 2

      对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

    9. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

      我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

    10. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

      使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

    随机推荐