我想知道需要采取什么预防措施,以便能够安全地从C++中的多个线程向libuv
事件循环添加回调。
更多详细信息
我有一些多线程C++ 11代码,我想对其进行修改以使用libuv
的网络通信API。我不想每次需要网络通信时都创建一个新的libuv
事件循环(因为这会占用资源)。因此,我在一个单独的线程中创建了一个libuv
循环(我通过注册“保持 Activity ”计时器来防止该循环关闭)。当前,此事件循环使用singleton传递给其他线程。然后,在循环运行时(从其他线程)注册回调。
我担心在注册新的回调时并发访问libuv
事件循环:当调用uv_tcp_init
时,显式传递了循环(而是指向循环的指针);当调用uv_tcp_connect
时,未明确提及循环,但指向它的指针存储在传递的uv_tcp_t
结构中。我没有检查过上述任何函数是否实际上修改了循环,但是我的直觉是至少其中一个必须这样做(否则,libuv
无法跟踪 Activity 句柄)。
我的第一个想法是在用于访问事件循环的单例中添加mutex
属性,并在调用上述任何函数时使用它来防止并发访问事件循环:
EventLoop & loop = EventLoop::get(); // Access the singleton
{
std::lock_guard<std::mutex> lock(loop.mutex_attribute);
// Register callbacks, etc
}
但是,这不能保护事件循环免受线程(成功获取锁)和某些libuv
内部函数(或由libuv
触发的注册回调)之间的并发访问的影响,因为后者不知道我使用单例来保护访问。我应该担心并发访问吗?我可以采取哪些步骤来减轻风险?
最佳答案
我解决的解决方案是不将句柄直接从其他线程添加到libuv
事件循环中,而是让其他线程将句柄添加到队列中(与指向事件循环的指针存储在同一单例中)。对队列的访问受mutex
保护。
然后,“保持 Activity ”计时器通过以下方式定期清空队列(计时器回调知道保护队列的mutex
):
libuv
事件循环注册该句柄(因为我们从libuv
事件循环内的回调中注册了该句柄,因此不应该存在并发访问的任何风险),并对该句柄执行任何其他所需的操作(在我的情况下,调用uv_tcp_init
和uv_tcp_connect
),关于c++ - Libuv:保护事件循环免受并发访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49757669/