Libuv:保护事件循环免受并发访问

时间:2018-04-10 15:33:30

标签: c++ multithreading c++11 libuv

我想知道在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触发的注册回调)之间的并发访问的影响,因为后者不知道我使用单身人士来保护访问权限。

我是否应该担心所说的并发访问?我可以采取哪些措施来降低风险?

1 个答案:

答案 0 :(得分:0)

我解决的解决方案是不直接从其他线程向libuv事件循环添加句柄,而是让其他线程向队列添加句柄(存储在与事件指针相同的单例中)环)。对队列的访问受mutex保护。

“keep-alive”计时器然后通过以下方式定期清空队列(计时器回调知道mutex保护队列):

  • 从队列中获取第一个句柄,
  • 使用libuv事件循环注册该句柄(因为我们从libuv事件循环中的回调中注册句柄,不应存在任何并发访问的风险),并执行任何其他操作此句柄需要的操作(在我的情况下,请致电uv_tcp_inituv_tcp_connect),
  • 重复,直到队列为空。