如何避免在覆盖go的默认信号处理程序时出现种族问题?

Ben :

tl; dr,如果信号可以在go运行时中随时处理,那么我们如何安全地使用signal.IgnoreSIGINT来避免在安装默认信号处理程序和main()运行我们的内部指令之间产生竞争

旅途中的文档进行包装/信号指出此有关的信号的默认行为

SIGHUP,SIGINT或SIGTERM信号导致程序退出。

因此,编写一个旋转CPU的golang二进制文件,按ctrl + c发送SIGINT,程序将退出。

现在,假设您要覆盖该行为。一种方法是忽略带有signal.Ignore(syscall.SIGINT)

但是现在考虑以下

package main

import (
    "fmt"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    fmt.Println("Looping, SIGINT will have default behavior")
    for start := time.Now(); time.Now().Before(start.Add(time.Second * 5)); {

    }
    signal.Ignore(syscall.SIGINT)
    fmt.Println("OK")

    for start := time.Now(); time.Now().Before(start.Add(time.Second * 5)); {

    }
}

在这里,我们有一个简单的golang二进制文件,它会循环5秒钟。这是一个繁忙的循环,因此我们知道我们不会通过在OS线程上浪费时间来参与协作式多任务处理。然后,它注册以忽略SIGINT。

如果尝试这样做,您会注意到,如果在前5秒钟内输入ctrl + c,程序将退出。这似乎是有道理的-我们正在获取默认的golang运行时信号处理行为,因为我们尚未通过调用来覆盖它signal.Ignore

现在也许我们可以通过将移动signal.Ignore到main()中的第一位来解决此问题,但是此程序证明的是go运行时不能保证默认信号处理程序不会在main()中的同步代码之前运行完成执行。

即使您移动它,我们似乎也在

  1. go运行时注册其默认信号处理程序的时间点,以及
  2. 我们的代码可以运行的最早点(main中的第一条(或第二条,如果需要创建通道)指令)

我找不到关于此的文档。Go运行时提供什么保证,使我完全确定信号不会在第1阶段和第2阶段之间到达?

星期二:

TL; DR:尽早抓住,例如,在的顶部main


正如评论所言,这似乎不是将其描述为问题的好方法,因为它在所有编程语言中都是通用的:如果您没有为设置信号处理程序syscall.SIGINT,则默认情况下会被杀死SIGINT,一旦拥有就不会。没错,但是任何程序在启动之前都可以杀死,然后才有机会开始捕获信号。不论编程语言如何,都是如此。它对C和C ++程序的影响与对Go程序的影响一样多。

因此,通常来说,您需要做的所有工作才能可靠地捕获或舍弃SIGINT信号,并尽可能避免种族歧视,那就是尽早使用信号,即在通道signal.Notify(ch, os.Interrupt)顶部附近1然后,您可以编写自己的非竞赛代码,以通过goroutines和渠道进行处理:mainch

  • 让您自己的goroutine读取频道,以查看是否/何时发送信号。
  • 使用自己的互斥锁管理程序让它读取另一个通道或某些共享存储区,以查看如何以及何时传递信号。
  • 当一个信号被发送,如果你要退出,电话os.Exit(或-可能是更好的使用os.Resetsyscall.SIGINT,然后交付自己syscall.SIGINT产生正确的操作系统级别的退出状态,“通过信号1杀害” 2)。如果信号应被忽略,只需放弃频道通知。

有点相关:最近有一个修复程序可以syscall.SIGPIPE处理。特别是,调用signal.Ignore(syscall.SIGPIPE)应忽略SIGPIPE,但不是。这似乎在Go 1.14中已修复。


1如软件包说明所述,故意捕获信号将绕过外壳中nohuptrap "" 1 2 15外壳中的任何“被忽略”状态如果您想检查一下,请使用此signal.Ignored功能。

2如果signal_unix.go导出了该dieFromSignal函数,则可以直接使用函数,但不能。拥有一个与操作系统无关的包装器,至少可以干净地尝试这种自杀是很好的。这甚至可以sigprocmask在操作系统级别使用,以使自杀尽可能地避免种族歧视。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

安装Go程序时出现问题

如何重写TextBuffer的默认信号处理程序

定义自己的处理程序时是否应该触发默认信号处理程序?

在Laravel中实现命令处理程序时出现问题

使用中断处理程序时如何避免全局变量?

如何避免在信号处理程序中使用printf?

从默认致命信号的信号处理程序返回

如果每个人使用的调试代码的机制都覆盖了它,那么如何捕获有问题的信号处理程序?

为什么这无效,但是在本地有效?— Codeforce中的国王种族问题

避免在Numba中出现种族状况

Python:如何覆盖默认日志记录处理程序?

在循环内附加事件处理程序时浏览器性能出现问题

启动应用程序时出现白屏的原因是什么?如何完全避免呢?

运行 HYPODD 程序时出现问题

运行处理程序时遇到问题?

当段故障发生时未调用信号处理程序时?

如何触发默认信号处理行为?

更改默认程序时如何打开css

在 Playstore 上传应用程序时如何处理许可证问题?

在Go中测试Lambda处理程序时如何模拟AWS Lambda上下文?

在Bluemix中构建Node.js应用程序时,如何覆盖node_modules的默认缓存?

QML:从其他元素覆盖信号处理程序

使用SIGINT默认处理程序时从system()返回值

dlang默认安装一些信号处理程序吗

将Python SIGINT重置为默认信号处理程序

使用日志记录处理程序时出现500错误

如何模拟Django信号处理程序?

如何模拟Django信号处理程序?

QML:如何实现孩子的信号处理程序