Я думаю, вы ищете неблокированную форму 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