【问题标题】:Event notification without mutex没有互斥锁的事件通知
【发布时间】:2013-03-30 17:12:42
【问题描述】:

C++11有std::condition_variable,它的等待函数是

template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate pred );

它需要一个互斥体。

据我了解 - 它的 notify_one 可以在不同步的情况下调用(我知道惯用的方法是将它与互斥锁一起使用)。

我有一个对象,它已经在内部同步 - 所以我不需要互斥锁来保护它。一个线程应该等待与该对象关联的某个事件,而其他线程会收到通知。

在 C++11 中如何在没有互斥体的情况下进行此类通知? IE。使用 condition_variable 很容易,但它需要一个互斥锁。我想过用一个假的互斥类型,但是std::mutex被钉在了等待界面。

一种选择是轮询 std::atomic_flag + sleep,但我不喜欢睡觉。

【问题讨论】:

    标签: c++ multithreading events c++11 condition-variable


    【解决方案1】:

    使用std::condition_variable_any,您可以使用任何实现BasicLockable 概念的类。

    对此我有一种不好的感觉,我检查了 libc++ 的std::condition_variable_any 的实现。事实证明,它使用了一个普通的std::condition_variable 和一个std::shared_ptr 到一个std::mutex,所以在没有深入挖掘的情况下肯定会涉及一些开销。 (这里有一些关于 SO 的其他帖子涵盖了这一点,尽管我首先必须搜索)
    因此,我可能会建议重新设计您的案例,以便同步实际上只能由保护普通条件变量的互斥锁完成。

    【讨论】:

    • 这正是我要找的,我不知道。谢谢!
    • “事实证明,它使用了一个普通的 std::condition_variable 和一个 std::shared_ptr 到一个 std::mutex,所以在没有深入挖掘的情况下肯定会涉及一些开销。” - 有趣的是,它会在 notify_one 中锁定内部互斥锁吗?普通的 std::condition_variable 怎么样 - 它是否使用 notify_one 锁定任何互斥锁?
    • “因此,我可能会建议重新设计您的案例,以便同步实际上只能由保护普通条件变量的互斥锁完成。” - 我不需要保护 notify_one。为什么我需要互斥锁,它只能在一个线程中使用?
    • @qble 是的,它锁定互斥体并立即释放它。普通的 std::condition_variable 只是调用底层的通知机制,然而这是所有定义的实现,因此依赖它不会让我感觉良好,也是我个人重新设计它的原因。
    • 对于好奇的人:condition_variable_any 的设计和实现的基本原理:open-std.org/jtc1/sc22/wg21/docs/papers/2007/… 在撰写本文时被称为gen_cond_var
    【解决方案2】:

    在某些线程模型中(尽管我怀疑现代模型),需要互斥锁来保护条件变量本身(不是您正在同步的对象)免受并发访问。如果条件变量不受互斥体保护,您可能会遇到条件本身的问题。

    Why do pthreads’ condition variable functions require a mutex?

    【讨论】:

    • 我认为 std::condition_variable_any::notify_one 不需要互斥锁来保护——即由 ISO 提供。如果某些架构需要保护 notify_one - 库会自行执行此操作,否则将不符合标准。
    • 有趣的信息,谢谢。我们绕了一圈。 std::condition_variable_any 拥有一个内部 std::mutex 来保护自己。 :-)
    • 这就是我的理解。如果 notify_one 不会被 ISO 同步 - 那么是的,我们需要外部互斥锁。
    【解决方案3】:

    我有一些对象,它已经在内部同步了——我不需要互斥锁来保护它。一个线程应该等待与该对象关联的某个事件,而其他线程会通知。

    如果您不持有互斥锁,则等待线程将错过通知,无论您是否使用 condition_variablecondition_variable_any 与内部互斥锁。

    您需要将至少一位额外信息与条件变量相关联,并且该位应由互斥体保护。

    【讨论】:

    • 是的,我知道这一点,在那种情况下这是可以接受的。
    • 你错过了我句子的结尾。如果在检查状态和等待条件变量时没有保持互斥锁,则存在竞争条件。
    • @qble - 请注意,该链接页面中“竞态条件”的定义与语言定义中“竞态条件”的定义相同。语言定义说,如果一个程序同时修改和读取一个变量并且这两个操作不同步,则存在竞争条件。它还说具有竞争条件的程序的行为是未定义的。因此,您可以猜测在您的系统上可能存在“非关键竞争条件”之类的东西,但如果不仔细检查您的系统规范,这不是您可以得出的结论。
    • @PeteBecker,您说的是 C++11 DATA RACE,是的,它是 UB,但与 RACE CONDITION 不同:“竞争条件或竞争危险是电子或软件系统的行为,其中输出取决于其他不可控事件的顺序或时间”。简而言之,即使您使用 mutex 来互斥两个线程 - 您 DO HAVE RACE CONDITION - 因为顺序是不可预测的,但没有 UB。在此处讨论的情况下 - 我们有 race condition 而不是 data race
    • @qble - 是的,正如我所说,我在谈论语言定义。如果您使用 C++ 同步对象,您必须从语言定义开始,而不是从某人在 Internet 上发布的内容开始。如果您想应用其他定义,请务必这样做,但要确保它是合适的,正如我所说,这意味着查看您正在使用的同步原语的保证,包括你的编译器为这些原语做的保证。
    猜你喜欢
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多