2011-10-25 2 views
1

Я реализую простую библиотеку окон в качестве расширения Ruby C. Windows имеет метод handle_events!, который входит в свой собственный цикл событий.Ruby C Extension: запускает цикл событий одновременно

Проблема в том, что я хочу один цикл событий для каждого окна и блоков метода. Я хочу, чтобы метод немедленно возвращался и позволял циклу запускаться в отдельном потоке. Какой был бы лучший способ достичь этого?

Я попробовал использовать , чтобы вызвать функцию цикла событий, а затем использовать rb_thread_call_with_gvl для вызова обратных вызовов окна, которые являются Proc. Полный исходный код можно найти here.

Он по-прежнему работает, но не так, как я предполагал: метод все еще блокируется. Возможно ли это с моделью резьбы Ruby?

+0

Ответ на [это] [1] вопрос может помочь вам. [1]: http://stackoverflow.com/questions/56087/does-ruby-have-real-multithreading –

ответ

0

У меня была та же самая проблема для решения. И поскольку rb_thread_call_with_gvl() был отмечен как экспериментальный в 1.9.2, и он не был экспортированным символом, я должен использовать другой подход:

Я назвал блокирующий handle_event! функцию из отдельного потока. Я использовал второй рубиновый поток, который был заблокирован в очереди сообщений. Блокируя очередь сообщений, gvl был выпущен с помощью rb_thread_blocking_region().

Если теперь поток, вызывающий handle_event! был разблокирован из-за события, он вытащил всю необходимую информацию для upcall Proc вместе в элементе очереди и нажал этот элемент в очередь. Рубиновый поток получил элемент, возвращенный из rb_thread_blocking_region() и, таким образом, повторно получил gvl и вызвал Proc с информацией из полученного элемента.

Сердечные приветы Торстен

0

Насколько я понимаю, используя rb_thread_call_with_gvl() все еще должно быть сделано в том же потоке. то есть речь идет о выпуске и принятии глобальной блокировки, а не об изменении потоков. Например, длинная работающая функция gzip может работать без блокировки, так что другие рубиновые потоки могут выполняться параллельно.

Если вы хотите, чтобы ваши Procs вызывали обратно в другой поток, разве вам не нужно создавать рубиновый поток для этих Procs? Затем в этом потоке вызовите с помощью rb_thread_call_without_gvl(), чтобы не удерживать GVL (разрешая запуск других рубиновых потоков), а затем, когда у вас есть событие в потоке вторичного окна, вызовите rb_thread_call_with_gvl(), чтобы захватить блокировку, а затем вы должны быть права, чтобы вызвать Прок в этой же теме.

Вот так, как я понимаю, это ... (не проделав расширения материала C очень долго.)

Смежные вопросы