Is libuv thread safe?
Asked Answered
B

1

16

I have created a new thread dedicated to a libuv run loop. The thread function looks something like this:

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

The ref counter increment keeps the thread alive and in a state to process libuv events. I hope to be able to cause the run loop to end, thus causing the thread to exit, by executing uv_unref on the main thread.

However, on inspecting the uv_ref source code I failed to see any guarantee that access to the reference counter variable would be synchronized during concurrent access. Additionally I did not see any yield calls to relinquish control to the operating system during the run loop, meaning the program will not cooperate well with other processes.

This leads me to believe that I am not using libuv in the right way. If someone could explain what I'm doing wrong, that would be great!

Bryna answered 12/12, 2012 at 11:41 Comment(0)
C
38

No, libuv is not thread safe in this way. You should use uv_async to signal the loop to exit. uv_async is the only thread-safe facility that libuv has.

It would look something like this:

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);
}

Now from the other thread you can signal this loop to exit by calling

uv_async_send(&exit_handle);

You need to take care to not call uv_async_send() before the other thread has finished setting up the loop and the uv_async handle. Recent version of libuv include the uv_barrier synchronization primitives that you could use; but the libuv version that ships with Node.js 0.8 doesn't support this yet, so you probably need to use pthread facilities to make this work.

On a side note, you seem to be calling uv_ref and uv_unref with a loop reference as the argument. In recent versions of libuv this has changed, you are now supposed to uv_ref and uv_unref a specific handle. See uv.h for details.

Customary answered 12/12, 2012 at 16:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.