Особенности реализации обработчиков сигналов Signal.trap
Как и при реализации обработчиков сигналов в C или большинстве других языков, весь код, переданный методу Signal.trap, должен быть реентерабельным. Если вы не знакомы с понятием реентерабельности, перед чтением остальной части документа необходимо ознакомиться с ним на Википедии или в других источниках.
Самое главное, что «безопасность потоков» не гарантирует реентерабельность; а такие методы, как Mutex#lock и Mutex#synchronize, которые обычно используются для обеспечения безопасности потоков, даже препятствуют реентерабельности.
Особенности реализации Ruby VM
Ruby VM откладывает выполнение обработчиков сигналов Signal.trap до момента, когда это безопасно для его внутренних структур данных, но он не знает, когда безопасно работать с структурами данных в вашем коде. Ruby реализует отложенную обработку сигналов, регистрируя короткие C-функции только с функциями, безопасными для обработки сигналов, в качестве обработчиков сигналов. Эти короткие C-функции выполняют только необходимое, чтобы сообщить VM о необходимости выполнить обработчики, зарегистрированные через Signal.trap, позже в основном потоке Ruby Thread.
Небезопасные методы для вызова в блоках Signal.trap
В случае сомнений, считайте любой метод, не указанный ниже как безопасный, небезопасным.
-
Mutex#lock, Mutex#synchronize и любой код, использующий их, явно небезопасен. Это включает
Monitorв стандартной библиотеке, который использует Mutex для обеспечения реентерабельности. -
Dir.chdirс блоком -
любые операции записи в
IO, когдаIO#syncимеет значение false; включаяIO#write,IO#write_nonblock,IO#puts. Каналы и сокеты по умолчанию имеют ‘IO#sync = true’, поэтому запись в них безопасна, еслиIO#syncне был отключен. -
File#flock, так как вызов underlying flock(2) не определен POSIX.
Обычно безопасные операции внутри блоков Signal.trap
-
Присваивание и получение локальных, экземпляра и класса переменных
-
Большинство операций выделения и инициализации объектов, включая
Array,Hash,String,Struct,Time. -
Общие операции с
Array,Hash,String,Struct, которые не выполняют блок, обычно безопасны; но будьте осторожны, если итерация происходит где-то еще. -
Hash#[],Hash#[]=(еслиHash.newне был вызван с небезопасным блоком) -
Thread::Queue#pushиThread::SizedQueue#push(с Ruby 2.1) -
Создание нового
Threadс помощьюThread.new/Thread.start, чтобы обойти невозможность использования Mutex внутри обработчика сигналов -
Signal.trapбезопасно использовать внутри блоков, переданных методуSignal.trap -
арифметические операции над
IntegerиFloat(‘+’, ‘-’, ‘%’, ‘*’, ‘/’)Кроме того, обработчики сигналов не выполняются между двумя последовательными обращениями к локальным переменным, поэтому сокращения, такие как ‘+=’ и ‘-=’, не приведут к гонке данных при использовании с
IntegerиFloatклассами в обработчиках сигналов.
Методы-обертки системных вызовов, безопасные внутри Signal.trap
Так как Ruby имеет обертки вокруг многих безопасных для обработки сигналов C-функций, соответствующие обертки для многих IO, File, Dir и Socket методов безопасны.
(Неполный список)
-
Dir.chdir(без аргумента блока)
…
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.