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

标签 c++ multithreading c++11 libuv

我想知道需要采取什么预防措施,以便能够安全地从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_inituv_tcp_connect),
  • 重复
  • 直到队列为空。
  • 关于c++ - Libuv:保护事件循环免受并发访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49757669/

    相关文章:

    c++ - 为什么我们需要模板模板参数的模板特化

    c++ - 使用 NS3 和 std::thread 的并行模拟

    c++ - vector 中的删除方法

    java - AWT 事件线程中断

    c# - 哪个线程最先进入临界区?

    c++ - 初始化时的求值顺序

    c++ - boost::condition_variable::notify_one() 的并发性

    c++ - 无法从 uint32_t* 转换为 LPDWORD

    java - 通过 Java 线程或 NDK pthread 加载 JNI 库?

    c++ - std::initializer_list 作为 std::array 构造函数