Spec-Zone.ru › Ruby 3.4

Предостережения при реализации callback-функций Signal.trap

Как и при реализации обработчиков сигналов на C или большинстве других языков, весь код, переданный в Signal.trap, должен быть реентерабельным. Если вы не знакомы с реентерабельностью, прежде чем читать остальную часть этого документа, ознакомьтесь с этой темой в Википедии или другом источнике.

Самое важное: «потокобезопасность» не гарантирует реентерабельность; а такие методы, как Mutex#lock и Mutex#synchronize, которые обычно используются для обеспечения потокобезопасности, даже препятствуют реентерабельности.

Особенность реализации виртуальной машины Ruby

Виртуальная машина Ruby откладывает выполнение callback-функций Signal.trap, пока это не станет безопасным для её внутренних структур данных, но она не знает, когда это безопасно для структур данных ВАШЕГО кода. Ruby реализует отложенную обработку сигналов, регистрируя короткие функции на C, в которых в качестве обработчиков сигналов используются только асинхронно-безопасные функции. Эти короткие функции на C лишь сообщают виртуальной машине, что нужно позднее выполнить callback-функции, зарегистрированные через 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, поскольку базовый вызов 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 (без аргумента block)

  • Dir.mkdir

  • Dir.open

  • File#truncate

  • File.link

  • File.open

  • File.readlink

  • File.rename

  • File.stat

  • File.symlink

  • File.truncate

  • File.unlink

  • File.utime

  • IO#close

  • IO#dup

  • IO#fsync

  • IO#read

  • IO#read_nonblock

  • IO#stat

  • IO#sysread

  • IO#syswrite

  • IO.select

  • IO.pipe

  • Process.clock_gettime

  • Process.exit!

  • Process.fork

  • Process.kill

  • Process.pid

  • Process.ppid

  • Process.waitpid

…

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API