脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Ruby - Ruby信号处理详解

Ruby信号处理详解

2022-08-28 12:21骏马金龙 Ruby

这篇文章主要介绍了Ruby信号处理详解,包含了Ruby使用Process.kill发送信号,Ruby使用trap()设置信号处理程序等需要的朋友可以参考下

Ruby使用Process.kill发送信号

?
1
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,表示探测是否能发送信号给目标进程,可探测是否能管理目标进程或者探测目标进程是否存活
?
1
2
3
4
5
6
pid = fork do
  sleep 300
end
# ...
Process.kill("HUP", pid)
Process.wait

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

Ruby中使用Kernel.trapSignal.trap捕获信号并设置信号处理程序,这两个trap等价。

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

?
1
2
3
4
5
6
7
8
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对象,因此,应该进行类型判断:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 第一次定义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())。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

子进程继承信号处理程序

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

更多关于Ruby信号处理的知识请查看下面的相关链接

原文链接:https://www.junmajinlong.com/ruby/ruby_signal/

延伸 · 阅读

精彩推荐
  • Rubyruby 实变量

    ruby 实变量

    一个实变量由@开头,它的范围限制在self对象内.两个不同的对象,即使属于同一个类,也可以拥有不同值的实变量.从对象外部来看,实变量不能改变甚至观察(比...

    脚本之家4692020-04-09
  • RubyRuby中Hash的11个问题解答

    Ruby中Hash的11个问题解答

    这篇文章主要介绍了Ruby中Hash的11个问题解答,本文讲解了如何创建Hash、Hash的键是哪些类型、 如何给Hash赋默认的值等内容,需要的朋友可以参考下 ...

    脚本之家3882020-04-20
  • RubyRuby中类变量和实例变量的比较

    Ruby中类变量和实例变量的比较

    这篇文章主要介绍了Ruby中类变量和实例变量的比较,本文讲解了4点类变量和实例变量的不同之处,并给出了代码实例,需要的朋友可以参考下 ...

    脚本之家2482020-04-30
  • RubyRuby实现插入排序算法及进阶的二路插入排序代码示例

    Ruby实现插入排序算法及进阶的二路插入排序代码示例

    插入排序即是把已有的有序序列从后向前扫描插入元素,数值大的向后移动,这里我们就来看一下使用Ruby实现插入排序算法及进阶的二路插入排序代码示例...

    织田信长4782020-05-11
  • Ruby用实际代码演示Ruby的容易被误解的6个特性

    用实际代码演示Ruby的容易被误解的6个特性

    这篇文章主要介绍了用实际代码演示Ruby的容易被误解的6个特性,采集自IBM官方网站的开发者文档,需要的朋友可以参考下 ...

    IBM developerWorks3642020-04-24
  • Ruby21个你应该知道的Ruby编程技巧

    21个你应该知道的Ruby编程技巧

    这篇文章主要介绍了21个你应该知道的Ruby编程技巧,涵盖编码过程中的方方面面,需要的朋友可以参考下 ...

    脚本之家2372020-04-14
  • RubyRuby实现的最长公共子序列算法

    Ruby实现的最长公共子序列算法

    这篇文章主要介绍了Ruby实现的最长公共子序列算法,本文直接给出实现代码,需要的朋友可以参考下 ...

    脚本之家3422020-04-30
  • Rubyruby 面向对象思维 概念

    ruby 面向对象思维 概念

    面向对象 是一个挺让人迷惑的措辞.叫一切东西都是面向对象会让别人觉得你很时髦.Ruby声称自己是面向对象的脚本语言;但究竟什么才是面向对象? 我们已经...

    ruby教程网3252020-04-08