go - 为什么子进程“sleep 10”没有终止?
问题描述
我需要测试一个进程是否终止,而我所拥有的只是它的 pid 号。为此,我测试伪文件“/proc/<pid>”是否存在。
为这个函数写一个测试,我注意到进程没有按预期终止。
对于测试,我运行“sleep 10”作为应该运行 10 秒的子进程。启动此过程后,我轮询伪文件“/proc/<pid>”的消失。该伪文件永远不会消失,也不会检测到子进程的终止。
测试 golang playground 的代码重现了问题: https: //play.golang.org/p/fb4CbXkIjh3。
我检查了该进程是否已创建,并且 pid 是否正确。在检查过程中可以看到它变成了<defunct>。它没有因此被删除。
问题如下:
- 为什么子进程不终止?
- 如何更改代码以使其终止?
package main
import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
"time"
)
func main() {
fmt.Println("Hello, playground")
cmd := exec.Command("sleep", "10")
if err := cmd.Start(); err != nil {
log.Fatal("unexpected error:", err)
}
pidStr := strconv.Itoa(cmd.Process.Pid)
log.Println("sleep pid:", pidStr)
for {
if _, err := os.Stat("/proc/" + pidStr); os.IsNotExist(err) {
log.Println("detect termination of /proc/" + pidStr)
return
}
log.Println("pgm /proc/" + pidStr + " is running")
time.Sleep(3 * time.Second)
}
}
解决方案
在操作系统级别,在任何与 POSIX 兼容的操作系统(Unix、Linux、Darwin 等)中,已完成但尚未被其上级收集的进程处于“已失效”或“僵尸”状态。它仍然存在,但不能被杀死:它已经死了。它的存在正是为了让它的上级——可以调用操作系统级系统调用的进程——可以wait
调用操作系统级wait
系统调用并看到该进程现在已经死了。
一旦它的上级等待它,该进程就真正被删除了:不再有一个僵尸进程占用该进程 ID。如果你有一个/proc
文件系统,这是进程从/proc
.
在 Go 中,调用cmd.Wait()
会调用操作系统级别的wait
调用,这就是执行此操作的方法。如果您想收集 this 的结果cmd.Wait()
,一个好方法是通过通道发送它。
(如果你想产生一个运行时间很长的进程而不是等待它,你可以放弃它,这样你就不再是它的上级了。正确执行此操作的细节充满了操作系统特定的小玩意儿,例如丢弃控制 tty , 设置会话, 使用procctl
or prctl
, 等等。)
推荐阅读
- gradle - 如何防止 gradle 任务覆盖由调用 groovy 类创建文件的自定义任务创建的文件
- swift - Swift:自定义注释丢失字幕
- django-forms - 如何使用 Crispy 表单将 action 和 novalidate 属性添加到表单标签
- android - 如何为 viewPager2 设置适配器
- angular - Angular:仅允许通过模板访问组件成员
- python-3.x - 如何使用 django restframework 构建 django 模板
- google-cloud-platform - 使用自定义预测例程时没有这样的文件或目录:'/tmp/model/0001' google cloud ai platform
- java - 依赖项更新后 gradle build 损坏
- python - 如何在布尔列上的 df 的几列中进行聚合?
- mongodb - 如何在 mongoDB 中重命名数据库?