Как я могу избежать нарушений по пересеченным потокам в расширении рубина?
-
04-10-2019 - |
Вопрос
Я пишу расширение C, предоставляя интерфейс между RUBY и асинхронной библиотекой ввода / вывода. При запуске тестов по моим коде я часто получаю ошибки, в том числе (но не ограничиваясь):
[BUG] cross-thread violation in rb_thread_schedule()
Asynchronous IO означает, что мое расширение C нужно будет доставлять сообщения в Ruby из нескольких потоков (не основной нить переводчика). Как мне избежать этих нарушений безопасности потоков, в процессе?
Решение
Для Ruby 1.8.x Единственный способ избежать ошибки, является очевидным - только вызывают только API Ruby / C из основного потока интерпретатора. Я считаю, что это относится к Ruby 1.9.x, но я не работал с ним и не знаю, как его родная поток может изменить вещи. Вместо того, чтобы иметь несколько местных потоков, напрямую призывающую API, вам нужно использовать Phance Pattern Projection / PhotoSer для доставки запросов из ваших вторичных нативных потоков к вашему коду в основной резьбе переводчика. И в идеале делают это, пока не излишне блокируя другие рубиновые зеленые нити. Если вы посмотрите на реализацию Ruby, планировщик Ruby Green Thread Essentia select()
петля. Это говорит о следующей общей структуре:
- Создать трубу или другой механизм IPC, который обеспечивает реальный
select()
-Облажный дескриптор файла. - Сокращать родные нити и предоставьте их с помощью конца трубы.
- В основной проводке переводчика введите цикл событий, которые вызывают
rb_thread_wait_fd()
на чтение трубы. Это позволит планировщику нити Ruby Gree для запуска других зеленых потоков. - Когда ваши вторичные родные потоки имеют запросы на основную нить, они их покинули, а также запишите на трубу, просыпаясь зеленой нитью, запущенную контуром событий.
Видеть rb_io_sysread()
(реализация IO#sysread
) Для чего, вероятно, самый простой чистый IO-с использованием функции в базе Ruby Code.