如何在Ruby中使用信号阻塞
在Ruby中如何阻止某些信号?(即sigprocmask,如下所述:) 下面是我的示例代码如何在Ruby中使用信号阻塞,ruby,signals,Ruby,Signals,在Ruby中如何阻止某些信号?(即sigprocmask,如下所述:) 下面是我的示例代码 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_int
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)
我是否可以在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
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
更新:我目前正在做类似的事情:
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
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
我认为你在寻找:
Signal.trap(信号、命令)→ obj
[…]
如果命令是字符串
“IGNORE”
或“SIG\u 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中信号处理的回顾:)然后您可以这样做:
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
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
Ruby返回与信号关联的最后一个处理程序,因此您可以使用:
def bypass_signal(name)
old_handler = trap("INT", 'IGNORE')
yield
trap("INT", old_handler)
end
bypass_signal "INT" { method_which_shouldnt_be_interrupted }
最后一个
trap
不应该是trap('INT','DEFAULT')
?@Simon:是的,应该是INT
,现在是:)谢谢。我的理解是,这种技术会使程序表现得好像信号从未发生过一样。不是这样吗?我有一些不应该被信号打断的代码;然而,这些信号仍然需要处理。当这些代码完成运行时,信号应该被处理。我想这更接近我所寻找的。但是,我不想被中断的代码仍然被中断。退出直到代码完成后才发生,但是信号仍然在“不可中断”代码的中间处理。这给我留下了一个问题(也许这才是真正的问题):这安全吗?我知道在C程序中有些情况下这是不安全的。Ruby在这种情况下“正常工作”吗?我真的需要担心信号会被屏蔽吗?另外,请看我的更新。我认为我目前所做的与你所建议的非常相似(有效)。也就是说,立即处理信号,但在不间断代码完成运行之前,不要进行工作(即退出)。作为跟进,Ruby不会为您处理此问题。例如,我在这一行有一个Errno::EINTR提升:/usr/local/rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/net/http.rb:644:in“initialize”。如果Ruby允许您阻止信号,HTTP请求将不会被中断。阻止信号和忽略信号是完全不同的。你的例子只是简单地忽略了这个信号。这意味着我的进程在运行方法时接收到的任何信号都不会被中断处理。这不是期望的行为。在C语言中,sigprocmask会在信号被阻塞时将其排队。一旦它们不再被阻止,这些信号将被发送。使用sigprocmask,不会丢失任何信号。这也将受益于begin。。。确保收益率。如果您使用确保
,我会向上投票