假设我有一个带有如下循环的程序:
#!/usr/bin/env ruby
puts $$
def do_work
puts Time.now
end
Signal.trap("HUP") do
do_work
end
loop do
sleep 60
do_work
end
它每60秒“有效”。有时我不想等待整整60秒,所以我立即将HUP
信号捕获到do_work
。这很好用,除了一件事:我想在处理信号后重置60秒钟。它现在设置的方式,如果睡眠是@ 45秒并且我发送程序SIGHUP
,它将do_work
然后15秒后再次do_work
。
如何使用上述约束对其进行重新设计?
答案 0 :(得分:1)
免责声明:我使用信号INT(由ctrl + C触发)测试我的代码,因为我在Windows上没有HUP。 http://en.wikipedia.org/wiki/Unix_signal#POSIX_signals让我相信HUP也应该正常工作,但我不能百分百肯定。
对于您列出的示例代码,您可以将sleep 60
从循环移动到do_work
方法内部:
def do_work
puts Time.now
sleep 60
end
Signal.trap("HUP") do
do_work
end
loop do
do_work
end
但是,可能有更好的方法来封装逻辑并使其可重复使用。以下是我提出的建议:
class Worker
attr_accessor :interval
attr_reader :times_worked
def initialize(interval, signal)
@signal = signal
@interval = interval
@times_worked = 0
end
def set_task(&block)
@work_to_do = block
Signal.trap(signal) { do_work }
start
end
def stop
@stop = true
end
def start
@stop = false
loop do
break if @stop
do_work
end
end
def do_work
@work_to_do.call
@times_worked += 1 # just an example of something you could put here
sleep @interval
end
end
worker = Worker.new(5, "HUP")
worker.set_task { puts Time.now }
答案 1 :(得分:1)
可能的解决方案:
q1, q2 = (0..1).map { Queue.new }
Thread.new do
loop do
time, seq = q1.pop
delta = time - Time.now
sleep delta if delta > 0
q2.push seq
end
end
Signal.trap("HUP") do
Thread.new do
q2.push nil
end
end
seq = 0
q2.push seq
loop do
# Drop expired sequences
while (event_seq = q2.pop; event_seq && event_seq != seq)
end
# If HUP expire current sequence
seq += 1 unless event_seq
# Do work here
p Time.now
q1.push [Time.now + 60, seq]
end