I would like to know what precautions are needed to be able to safely add callbacks to a libuv
event loop from multiple threads in C++.
More details
I have some multi-threaded C++11 code that I want to modify to use make use of libuv
's network communication API. I do not want to create a new libuv
event loop every time network communication is required (for that would use up resources). So I created a libuv
loop in a separate thread (I prevent the loop from closing by registering a "keep-alive" timer). This event loop is currently passed to other threads using a singleton. Callbacks are then registered (from other threads) while the loop is running.
I am worried about concurrent accesses to the libuv
event loop when registering new callbacks: when calling uv_tcp_init
the loop is explicitly passed (rather, a pointer to the loop); when calling uv_tcp_connect
the loop is not explicitly mentioned but a pointer to it is stored in the uv_tcp_t
struct passed. I haven't checked whether any of the above-mentioned functions actually modify the loop, but my intuition is at least one of them must do to (otherwise, libuv
couldn't keep track of active handles).
My first thought was to add a mutex
attribute to the singleton used to access the event loop and use it to prevent concurrent access to the event loop when calling any of the above functions:
EventLoop & loop = EventLoop::get(); // Access the singleton
{
std::lock_guard<std::mutex> lock(loop.mutex_attribute);
// Register callbacks, etc
}
However, this does not protect the event loop from concurrent accesses between my thread (which successfully acquired the lock) and some libuv
internal function (or a registered callback triggered by libuv
) since the latter are not aware of my using a singleton to protect access.
Should I be worried about said concurrent accesses? What steps may I take to mitigate the risks?