1

active_record 对 windows 下的信号处理做了什么(我在 mac 上没有看到相同的版本)导致它的行为如此奇怪?例如:

require 'rubygems'
trap("INT"){puts "interrupted"}
puts __LINE__
sleep 5
require 'active_record'
trap("INT"){puts "interrupted again"}
puts __LINE__
sleep 5

当我运行上面的代码(ruby 1.8.6,gem 1.3.1,activerecord 2.2.2)时,我可以在第一次睡眠期间多次点击 ^C,但是在需要 activerecord 之后的第一次中断会导致脚本终止。在上述情况下,陷阱仍然执行,只是无法让程序继续执行。通常。

删除第二个陷阱调用对行为没有任何影响。

真正令人烦恼的是,在某些情况下,陷阱根本无法执行。考虑到这样做的全部目的是让我的代码自行清理(删除它在数据库中的足迹,以便下一个人看到一个理智的状态),这是一个真正的问题。例如:

require 'rubygems'
require 'active_record'
trap("INT"){puts "interrupted"}
puts __LINE__
gets

在看到 puts 后按 ^C 根本不会执行陷阱。

我只在需要 active_record 后才看到这个问题。有解决方法吗?我很想知道这是一个错误还是有某种解释。正如我所说,我在 mac 上对此没有任何问题 - 重复 ^Cs 会导致陷阱 proc 的多次执行。

谢谢...

4

2 回答 2

1

考虑到这样做的全部目的是让我的代码自行清理(删除它在数据库中的足迹......

您是否考虑过仅使用数据库事务?似乎这将是解决问题的一种更简单的方法。

于 2009-04-16T00:20:17.803 回答
0

尝试复制此问题时,我看到了不同的模式:

puts "start"
trap("INT") { puts "interrupted" }
sleep 5
puts "end"

在 Ubuntu (Ruby 1.8.6) 上,这会产生

start
interrupted
interrupted
(etc)
interrupted
end

因此,每次按下 Crtl-C 时都会“中断”打印,直到 5 秒结束。在 Windows(也是 Ruby 1.8.6)下,这会产生:

start
interrupted
end

即它打印一次“中断”然后退出。

因此,在处理 SIGINT 时,Ruby 似乎退出了睡眠例程并继续执行下一条语句。我的猜测(挥手)是这在某种程度上是由于 Ruby 在 Windows 上使用绿色线程而不是本机线程。请各位高手在这里指点一下。

sleep您可以通过在处理程序中重新启动来模拟 Unix-y 行为:

puts "start"
trap("INT") do 
  puts "interrupted"
  sleep 5
end
sleep 5
puts "end"

不幸的是,每次 SIGINT 被捕获时都会重置计时器,所以它需要一些黑客攻击:

$interval = 5
def go_to_sleep(secs)
  $started = Time.now
  sleep secs
end
trap("INT") do 
  puts "interrupted"
  time_to_sleep = [0,$interval - (Time.now - $started)].max
  if time_to_sleep > 0
    sleep time_to_sleep
  end
end
puts "one"
go_to_sleep($interval)
puts "two"
go_to_sleep($interval)
puts "three"
go_to_sleep($interval)
于 2010-01-20T02:57:48.990 回答