【问题标题】:Libuv: protecting the event loop from concurrent accessesLibuv:保护事件循环免受并发访问
【发布时间】:2018-04-10 15:33:30
【问题描述】:

我想知道需要采取哪些预防措施才能从 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 触发的注册回调)之间的并发访问,因为后者不知道我使用单例来保护访问。

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

    • 您可以在从另一个线程添加回调时写入 PIPE 以触发主线程中的回调(然后从队列中添加回调)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 2016-06-23
    相关资源
    最近更新 更多