Как избежать нарушений между потоками в расширении Ruby? - PullRequest
5 голосов
/ 20 сентября 2010

Я пишу расширение C, предоставляющее интерфейс между Ruby и библиотекой асинхронного ввода-вывода.При выполнении тестов над моим кодом я часто получаю ошибки, включая (но не ограничиваясь):

[BUG] cross-thread violation in rb_thread_schedule()

Асинхронный ввод-вывод означает, что моему расширению C потребуется доставлять сообщения на ruby ​​из нескольких потоков (не основного интерпретатора)нить).Как избежать этих нарушений безопасности потоков, в процессе?

1 Ответ

7 голосов
/ 21 сентября 2010

Для ruby ​​1.8.x единственный способ избежать ошибки - очевидный - вызывать только Ruby / C API из основного потока интерпретатора.Я полагаю, что это относится и к ruby ​​1.9.x, но я не работал с ним и не знаю, как его нативная поддержка потоков может изменить ситуацию.Вместо того, чтобы несколько собственных потоков напрямую вызывали API, вам нужно использовать шаблон «производитель / потребитель» для доставки запросов от ваших вторичных собственных потоков к вашему коду в основном потоке интерпретатора.И в идеале делать это, не бесполезно блокируя другие зеленые рубиновые темы.Если вы посмотрите на реализацию ruby, планировщик зеленых потоков ruby ​​представляет собой цикл select().Это предполагает следующую общую структуру:

  • Создайте канал или другой механизм IPC, который предоставляет настоящий select() -данный дескриптор файла.
  • Создайте собственные потоки и предоставьте им записьконец канала.
  • В главном потоке интерпретатора введите цикл обработки событий, который вызывает rb_thread_wait_fd() на конце чтения канала.Это позволит планировщику зеленых потоков ruby ​​запускать другие зеленые потоки.
  • Когда ваши вторичные собственные потоки получают запросы для основного потока, они ставят их в очередь и также записывают в канал, пробуждая зеленый поток, выполняющий ваше событиеloop.

См. rb_io_sysread() (реализация IO#sysread) о том, что, вероятно, является самой простой чистой функцией использования ввода-вывода в базе кода ruby.

...