Using the same event loop from different threads is not safe. Very
few functions in libuv are thread-safe; if the documentation for a
function does not explicitly mention that it's thread-safe, then you
can safely assume it's not.
Using an uv_async_t handle should work with two caveats:
a) libuv can (and will) coalesce multiple calls to uv_async_send()
into a single call to the async callback, and
b) you're adding a fair amount of overhead per datagram that way so
you may not achieve very high throughput
An alternative approach would be to create two event loops, one per
thread and each with its own UDP socket. Receive datagrams in one
thread and send datagrams from the other thread, done. (Only call
uv_udp_recv_start() in one thread, of course.)
It's possible to bind both sockets to the same port by creating an
IPC-capable pipe server and using that to send over the socket to the
other thread. See test/benchmark-multi-accept.c for an example.