如何阻止Ruby中的某些信号? (即.sigprocmask,如下所述:http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_21.html#SEC371)
这是我的示例代码
pid = fork do
trap('INT') do
puts "Graceful shutdown..."
puts "goodbye"
exit 0
end
loop do
this_could_be_interrupted
something_that_must_not_be_interrupted
this_could_be_interrupted_too
end
end
sleep 5
Process.kill('INT', pid)
我可以将something_that_must_not_be_interrupted
包装在ruby块中,以确保在该方法运行时不会处理SIGINT吗?
我想理想的是,如果我可以做这样的事情:
Process.block_signal('INT') do
something_that_must_not_be_interrupted
end
更新:我目前正在做类似的事情:
trap('INT') do
@interrupted = true
end
loop do
exit 0 if @interrupted
something_that_must_not_be_interrupted
end
答案 0 :(得分:14)
我认为你正在寻找non-block form of trap
:
Signal.trap( signal, command ) → obj
[...]
如果命令是字符串"IGNORE"
或"SIG_IGN"
,则信号将被忽略。如果命令是"DEFAULT"
或"SIG_DFL"
,则将调用Ruby的默认处理程序。
所以你应该能说出来:
trap('INT', 'IGNORE')
something_that_must_not_be_interrupted
trap('INT', 'DEFAULT')
更新:从评论中看,您似乎只想暂时忽略该信号。用你已经拥有的东西做最简单的方法就是添加一个你的信号处理程序可以看到的标志,然后记住它进来时的信号,我们当前忽略了信号,当我们不再忽略你的东西时只需将信号队列发送给自己即可清空信号队列。如果把这个逻辑包装在一个类中,你会有一些相当友好的东西:
#
# Threading and race condition issues are left as an exercise,
# this is just meant as an illustration. Handling multiple signals
# at once is also left as an exercise.
#
class SignalHandler
def initialize(signal)
@interuptable = true
@enqueued = [ ]
trap(signal) do
if(@interuptable)
puts "Graceful shutdown..."
puts "goodbye"
exit 0
else
@enqueued.push(signal)
end
end
end
# If this is called with a block then the block will be run with
# the signal temporarily ignored. Without the block, we'll just set
# the flag and the caller can call `allow_interuptions` themselves.
def dont_interupt
@interuptable = false
@enqueued = [ ]
if(block_given?)
yield
allow_interuptions
end
end
def allow_interuptions
@interuptable = true
# Send the temporarily ignored signals to ourself,
# see http://ruby-doc.org/core/Process.html#method-c-kill
@enqueued.each { |signal| Process.kill(signal, 0) }
end
end
真正的功能代码是解释技术的最简单方法(我必须编写它以确保该技术可行)所以你去。感谢Ruby中对信号处理的审查:)那么你可以这样做:
sigint = SignalHandler.new('INT')
loop do
this_could_be_interrupted
sigint.dont_interupt { something_that_must_not_be_interrupted }
this_could_be_interrupted_too
end
答案 1 :(得分:5)
Ruby返回与信号关联的最后一个处理程序,因此您可以使用:
def bypass_signal(name)
old_handler = trap("INT", 'IGNORE')
yield
trap("INT", old_handler)
end
bypass_signal "INT" { method_which_shouldnt_be_interrupted }