Ruby, windows, active_record и Control-C

Что делает 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 вызывает скрипт для прекращения. В вышеприведенном случае ловушка все еще выполняется, она только не позволяет программе продолжаться. Обычно.

Удаление второго вызова trap не влияет на поведение.

Настоящее раздражение в том, что в некоторых условиях ловушка вообще не срабатывает. Учитывая, что весь смысл в этом состоит в том, чтобы заставить мой код очищаться после себя (удалить его след в базе данных, чтобы следующий парень увидел нормальное состояние), это реальная проблема. Например:

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

Нажатие ^C после просмотра пут не будет вообще выполнять ловушку.

Я вижу эту проблему только после запроса active_record. Есть ли обходной путь? Мне было бы интересно узнать, если это ошибка или есть какое-то объяснение. Как я уже сказал, у меня нет проблем с этим на Mac - повторяющиеся ^Cs приводят к многократному выполнению процесса trap.

Спасибо...

2 ответа

Учитывая, что весь смысл в этом состоит в том, чтобы заставить мой код очищаться после себя (удалить его след в базе данных...

Рассматривали ли вы просто использование транзакции базы данных? Кажется, что это был бы гораздо более простой способ решить проблему.

Я увидел другую картину при попытке дублировать эту проблему:

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. Любые эксперты, пожалуйста, перезвоните здесь.

Вы можете эмулировать поведение Unix-y, перезапустив sleep в обработчике:

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)
Другие вопросы по тегам