#ruby #multithreading #fork #child-process
Вопрос:
Это работает так, как и ожидалось:
signals = %w[INT TERM]
signals.each do |signal|
Signal.trap(signal) do
puts "trapping the signal and sleeping for 5 seconds"
sleep 5
puts "done, exiting"
exit
end
end
sleep 100
так же как и это:
# ...signal trap code from above...
t = Thread.new{ sleep 10 }
t.join
так же как и это:
# ...signal trap code from above...
`sleep 10`
однако это не означает:
# ...signal trap code from above...
t = Thread.new{ `sleep 10` }
t.join
Для первых трех запуск кода, а затем немедленная отправка control-c
результатов в ruby, ожидание 5 секунд перед выходом.
Для четвертого, запуск кода, а затем немедленная отправка control-c
результатов в ruby, немедленно завершается. Что удивительно, так это то, что два puts
сообщения, «захват…» и «готово…», оба напечатаны, но sleep 5
промежуточное между ними, по-видимому, пропущено.
использование terrapin вместо обратных ссылок дает еще одну подсказку — terrapin жалуется, что дочерние процессы вышли из ненулевого состояния. при попытке распечатать этот статус он ничего не печатает, возможно, предполагая, что процесс был бесцеремонно жестко прерван.
Таким образом, похоже, что у ruby есть какое-то поведение по умолчанию в отношении дочерних процессов, созданных в потоках, которые не являются основным потоком. Я подозревал, что это может быть сделано специально, но я не смог найти никакой документации или обсуждения по этому поводу.
Я тоже пытался
t = Thread.new{ `ls -R /` }
вместо сна, на всякий случай, было какое-то взаимодействие с конкурирующими реализациями сна, такое же поведение.
Почему это происходит?
Больше Экспериментов
Это также ведет себя так, как и ожидалось. он ожидает завершения подпроцесса в потоке 10 секунд. таким образом, странное поведение происходит только в контексте сигнальной ловушки.
thread = Thread.new { `sleep 10` }
thread.join
Чтобы проверить, происходит ли что-то, связанное с одновременным захватом сигнала подпотоком, либо по замыслу, либо из-за ошибки. Но это ведет себя так, как и ожидалось:
@main_thread = Thread.current.object_id
puts "main thread: #{@main_thread}"
signals = %w[INT TERM]
signals.each do |signal|
Signal.trap(signal) do
puts Thread.current.object_id
next unless Thread.current.object_id == @main_thread
puts "thread from trap: #{Thread.current.object_id}"
puts "trapping the signal and sleeping for 5 seconds"
sleep 5
puts "done, exiting"
exit
end
end
Комментарии:
1. Вы устанавливаете ловушку в своем основном процессе, а не в каждом потоке, поэтому я ожидал бы такого поведения как неподготовленный SIGTERM.
2. afaik, ловушки предназначены для каждого процесса, так что это не должно иметь значения… но да, мне интересно, связано ли что-то в этом роде