我想知道在C ++中从多个线程安全地向libuv
事件循环添加回调所需的注意事项。
更多详情
我有一些多线程C ++ 11代码,我想修改它以使用libuv
的网络通信API。每次需要网络通信时,我都不想创建一个新的libuv
事件循环(因为这将占用资源)。所以我在一个单独的线程中创建了一个libuv
循环(我通过注册" keep-alive"计时器来阻止循环关闭)。此事件循环当前使用singleton传递给其他线程。然后在循环运行时注册(从其他线程)回调。
我担心在注册新回调时对libuv
事件循环的并发访问:当调用uv_tcp_init
时,显式传递了循环(而不是指向循环的指针);在调用uv_tcp_connect
时,没有明确提到循环,但是指向它的指针存储在传递的uv_tcp_t
结构中。我还没有检查上述任何一个函数是否真的修改了循环,但我的直觉至少是其中一个必须做的(否则libuv
无法跟踪活动句柄)。
我的第一个想法是在用于访问事件循环的单例中添加mutex
属性,并在调用上述任何函数时使用它来阻止对事件循环的并发访问:
```
EventLoop & loop = EventLoop::get(); // Access the singleton
{
std::lock_guard<std::mutex> lock(loop.mutex_attribute);
// Register callbacks, etc
}
```
但是,这不保护事件循环不受我的线程(成功获取锁)和某些libuv
内部函数(或libuv
触发的注册回调)之间的并发访问的影响,因为后者不知道我使用单身人士来保护访问权限。
我是否应该担心所说的并发访问?我可以采取哪些措施来降低风险?
答案 0 :(得分:0)
我解决的解决方案是不直接从其他线程向libuv
事件循环添加句柄,而是让其他线程向队列添加句柄(存储在与事件指针相同的单例中)环)。对队列的访问受mutex
保护。
“keep-alive”计时器然后通过以下方式定期清空队列(计时器回调知道mutex
保护队列):
libuv
事件循环注册该句柄(因为我们从libuv
事件循环中的回调中注册句柄,不应存在任何并发访问的风险),并执行任何其他操作此句柄需要的操作(在我的情况下,请致电uv_tcp_init
和uv_tcp_connect
),