Я создал новый поток, посвященный циклу выполнения libuv. Функция потока выглядит примерно так:
void thread_function()
{
uv_loop_t *loop = uv_loop_new();
uv_ref( loop );
uv_run( loop );
}
Приращение счетчика ссылок поддерживает работу потока и позволяет обрабатывать события libuv. Я надеюсь, что смогу завершить цикл выполнения, вызывая выход из потока, выполнив uv_unref
в основной теме.
Тем не менее, при проверке uv_ref
Исходный код Я не увидел никакой гарантии, что доступ к переменной счетчика ссылок будет синхронизирован во время одновременного доступа. Кроме того, я не видел никаких вызовов yield для передачи управления операционной системе во время цикла выполнения, что означает, что программа не будет хорошо взаимодействовать с другими процессами.
Это заставляет меня поверить, что я не использую libuv правильным образом. Если бы кто-то мог объяснить, что я делаю неправильно, это было бы здорово!
Нет, libuv не является потокобезопасным в этом смысле. Вы должны использовать uv_async, чтобы дать сигнал циклу выйти. uv_async — единственное поточно-ориентированное средство, которое есть в libuv.
Это будет выглядеть примерно так:
uv_async_t exit_handle;
void exit_async_cb(uv_async_t* handle, int status) {
/* After closing the async handle, it will no longer keep the loop alive. */
uv_close((uv_handle_t*) &exit_handle, NULL);
}
void thread_function() {
uv_loop_t *loop = uv_loop_new();
/* The existence of the async handle will keep the loop alive. */
uv_async_init(loop, &exit_handle, exit_async_cb);
uv_run(loop);
}
Теперь из другого потока вы можете дать сигнал этому циклу выйти, вызвав
uv_async_send(&exit_handle);
Вы должны заботиться, чтобы не звонить uv_async_send()
до того, как другой поток завершит настройку цикла и дескриптора uv_async. Последние версии libuv включают uv_barrier примитивы синхронизации, которые вы можете использовать; но версия libuv, поставляемая с Node.js 0.8, пока не поддерживает это, поэтому вам, вероятно, нужно использовать средства pthread, чтобы это работало.
На заметку, вы, кажется, звоните uv_ref
а также uv_unref
со ссылкой на цикл в качестве аргумента. В последних версиях libuv это изменилось, теперь вы должны uv_ref
а также uv_unref
конкретная ручка. Увидеть uv.h для деталей.
Других решений пока нет …