在Racket程序停止后子过程仍然存在

时间:2016-09-06 22:29:34

标签: shell process racket zombie-process

我有以下程序可以旋转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*时,这个问题就消失了。有什么我可以做的,以确保我终止程序时我的子进程停止了吗?

1 个答案:

答案 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*函数返回的回调来做。

相关问题