Для 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.