我有以下程序可以旋转100个不同的进程(是的,我知道我应该关闭端口,我只是在这个例子中没有这样做):
#lang racket ; evil.rkt
(require compiler/find-exe)
(for ([i (in-range 100)])
(process* (find-exe) "-e" "(let loop () (loop))"))
正如所料,当我运行此程序并运行ps -fe | grep 'racket'
以获取运行racket的所有进程的列表时,我看到类似的内容:
....
73187 ?? 0:00.47 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73188 ?? 0:00.44 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73189 ?? 0:00.45 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73190 ?? 0:00.45 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73191 ?? 0:00.43 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73192 ?? 0:00.41 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73193 ?? 0:00.39 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73194 ?? 0:00.35 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73195 ?? 0:00.34 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73196 ?? 0:00.34 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
73197 ?? 0:00.29 /Users/leif/racket/racket/bin/racket -e (let loop () (loop))
....
问题在于,即使程序终止,这些进程仍在运行。
如果我在shell中运行它,并按Ctr + C终止程序,大多数进程都会停止。但是,偶尔会有一两个人继续跑步。
当我切换到使用process
而不是process*
时,这个问题就消失了。有什么我可以做的,以确保我终止程序时我的子进程停止了吗?
答案 0 :(得分:4)
这里的问题是,默认情况下,当程序终止时,托管人不会关闭由Racket生成的子进程。
process
没有此问题的原因是process
函数启动了一个shell(例如/bin/sh
)并在其中运行您的命令。那个shell正在处理子进程。另一方面,process*
直接运行你的子进程,因此Racket负责它,或者它将成为一个僵尸进程。
当你在shell(而不是DrRacket)中运行它时,这个问题要小得多,这是因为你的shell可能在你自己的进程组中拥有你的进程及其所有子进程。因此,当按下Ctr + C时,shell会向进程组中的所有进程发送SIGINT,其中包括进程的所有子进程。偶尔,不幸的是,有些进程太新了,无法添加到组中(或者它们是在SIGINT发送后的瞬间创建的,我不完全确定这里的机制),因此它们仍处于活动状态。
所有这一切都可以通过将current-subprocess-custodian-mode
参数设置为'kill
(或'interrupt
)来解决,以便Racket custodian在终止之前终止您的流程。因此,修改代码将如下所示:
#lang racket
(require compiler/find-exe)
(parameterize ([current-subprocess-custodian-mode 'kill])
(for ([i (in-range 100)])
(process* (find-exe) "-e" "(let loop () (loop))")) )
(请注意,这仍然依赖于Racket来关闭子进程。如果使用像ffi/unsafe
这样的库并导致Racket出现段错误,则子进程仍将运行。)
作为附录,请注意,只有在程序结束时(或者当前保管人关闭时,例如在沙盒中),该过程才会死亡,如果您想要在您必须发送之前停止子流程它本身就是一个中断/终止信号,你可以用process*
函数返回的回调来做。