当前位置: 代码网 > it编程>前端脚本>Ruby > Ruby信号处理详解

Ruby信号处理详解

2024年05月15日 Ruby 我要评论
ruby使用process.kill发送信号process.kill(signal, pid, ...) → integerprocess.kill发送指定的信号给一个或多个进程或进程组:如果目标pi

ruby使用process.kill发送信号

process.kill(signal, pid, ...) → integer

process.kill发送指定的信号给一个或多个进程或进程组:

  • 如果目标pid>0,表示发送信号给指定pid的进程
  • 如果目标pid=0,表示发送信号给调用kill的进程所在进程组的所有进程
  • 如果目标pid<0,表示按照操作系统的规则发送信号。对于linux来说:
    • 如果pid=-1,表示发送信号给除pid=1的init进程外的所有进程,当然,没有权限的进程将不受影响
    • 如果pid<-1,表示发送信号给-pid所在进程组的所有进程,例如-3000表示发送信号给pid=3000的进程所在进程组的所有进程

process.kill的第一个参数是要发送的信号:

  • 信号可以是字符串格式的信号名或数值格式的信号id,int或sigint或1都是有效的信号
  • 如果信号带有负号(如-2-int),表示发送信号给进程所在进程组而非指定的进程(linux不支持带负号的信号)
  • 如果信号为0,表示探测是否能发送信号给目标进程,可探测是否能管理目标进程或者探测目标进程是否存活
pid = fork do
  sleep 300
end
# ...
process.kill("hup", pid)
process.wait

ruby使用trap()设置信号处理程序

ruby中使用kernel.trapsignal.trap捕获信号并设置信号处理程序,这两个trap等价。

可设置多个trap来监控多个信号。

signal.trap(0, proc { puts "terminating: #{$$}" })
signal.trap("cld")  { puts "child died" }
fork && process.wait
=begin
terminating: 27461
child died
terminating: 27460
=end

trap的第一个参数是监控的信号名称,可以是字符串的信号名称(如sigint),可以是省略sig前缀的信号名称(如int),可以是信号对应的数值(如2)。

ruby支持一个特殊的信号0(对应的字符串信号名为exit或sigexit),表示进程退出时会触发的信号。

trap的第二个参数或语句块是捕获到信号后执行的代码。第二个参数有几种特殊情况:

  • 如果第二个参数为字符串ignoresig_ign,表示忽略本次捕获的信号
  • 如果第二个参数为字符串defaultsig_dfl,表示按照ruby的默认处理规则来处理
  • 如果第二个参数为字符串exit,表示以退出状态码0退出当前进程
  • 如果第二个参数为字符串system_default,表示按照系统的默认信号处理规则来处理,即以退出状态码141退出进程

避免信号覆盖

使用第三方包的时候,有时候不知道这个包是否定义了某个信号的信号处理程序,或者知道它定义了某信号信号处理程序,但自己定义这个信号的信号处理程序时,不想覆盖第三方包中所定义的处理程序。

这时,应该利用好trap的返回值。每一次trap设置信号处理程序时,都返回本信号之前已经定义的信号处理程序(是一个proc对象)。只是需要注意,有些信号的初始处理程序是一个字符串值default而不是一个proc对象,因此,应该进行类型判断:

# 第一次定义int的信号处理程序
first_trap = trap('int') { 
  first_trap.call if first_trap.is_a? proc
  puts "first_trap" 
}

# 第二次定义int的信号处理程序
old_trap = trap('int') { 
  old_trap.call if old_trap.is_a? proc   # 调用第一次定义的信号处理程序
  puts "old trap"  # 本次trap时执行的逻辑
}
# 定义好之后,old_trap为第一次定义的信号处理程序

# 之后按下ctrl+c触发int信号的信号处理程序

多线程信号注册问题

如果是在多线程中注册信号处理程序,该信号处理程序将总是注册在所在进程的main线程中(即使是在其它线程中设置trap())。

pid = fork do
  puts "main thread: #{thread.current}"
  thread.new {
    puts "new thread: #{thread.current}"
    trap("term", proc { puts "signal: #{thread.current}" })
    sleep 2
  }
  sleep 2
end

sleep 1
process.kill 'sigterm', pid
=begin
main thread: #<thread:0x00007fffd6ed4c10 run>
new thread: #<thread:0x00007fffd714f2b0@a.rb:4 run>
signal: #<thread:0x00007fffd6ed4c10 run>
=end

子进程继承信号处理程序

子进程会从父进程继承信号处理程序。

trap 'term', proc { puts "signal: #{process.pid}" }
puts "parent: #{process.pid}"

pid = fork do
  sleep 30
end

puts "child: #{pid}"
process.kill 'term', pid
=begin
parent: 2872
child: 2901
signal: 2901
=end
(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com