16

libuv実行ループ専用の新しいスレッドを作成しました。スレッド関数は次のようになります。

void thread_function()
{
  uv_loop_t *loop = uv_loop_new();
  uv_ref( loop );
  uv_run( loop );
}

refカウンターのインクリメントにより、スレッドは存続し、libuvイベントを処理できる状態に保たれます。uv_unrefメインスレッドで実行することにより、実行ループを終了させ、スレッドを終了させることができるようにしたいと考えています。

ただし、uv_refソースコードを調べたところ、同時アクセス中に参照カウンター変数へのアクセスが同期されるという保証はありませんでした。さらに、実行ループ中にオペレーティングシステムへの制御を放棄するためのyield呼び出しは見られませんでした。つまり、プログラムは他のプロセスとうまく連携しません。

これにより、私はlibuvを正しい方法で使用していないと信じるようになります。誰かが私が間違っていることを説明できれば、それは素晴らしいことです!

4

1 に答える 1

38

いいえ、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同期プリミティブが含まれています。ただし、Node.js 0.8に同梱されているlibuvバージョンはまだこれをサポートしていないため、これを機能させるにはおそらくpthread機能を使用する必要があります。

ちなみに、あなたは引数としてループ参照を呼び出しているようですuv_refuv_unreflibuvの最近のバージョンでは、これが変更されてuv_refおりuv_unref、特定のハンドルを使用することになっています。詳細については、 uv.hを参照してください。

于 2012-12-12T16:47:28.827 に答える