C++ 使用互斥体读取共享数据是否会导致任意陈旧的数据?

C++ 使用互斥体读取共享数据是否会导致任意陈旧的数据?,c++,multithreading,mutex,C++,Multithreading,Mutex,假设我们有一个简单的类: class example { bool m_isCanceled; example() : m_isCanceled(false) {} public: void cancel() { m_isCanceled = true; } void doWork() { for (int i = 0; i < MAX_RETRIES; ++i) { // Slow

假设我们有一个简单的类:

class example
{
    bool m_isCanceled;
    example() : m_isCanceled(false) {}
public:
    void cancel() { m_isCanceled = true; }

    void doWork()
    {
        for (int i = 0; i < MAX_RETRIES; ++i)
        {
            // Slow
            doStuff();

            if (m_isCanceled)
            {
                return;
            }
        }
    }
}
类示例
{
布尔穆被取消;
示例():m_isCanceled(false){}
公众:
void cancel(){m_isCanceled=true;}
无效销钉()
{
对于(int i=0;i
如果我们在一个线程上调用
example::doWork()
,然后在另一个线程上调用
example::cancel()
,那么在第一个线程看到
m\u isCanceled
现在为真之前,有没有时间限制


在类似的情况下,我建议我们用互斥来保护m_,但我的同事说,第一个线程最多会在额外的迭代后看到更新。这是对的吗?

根本没有保证。理想情况下,可以将布尔变量设置为原子变量。如果做不到这一点,使其在几乎所有已知平台上都能正常工作。当然,用互斥来保护它是可以保证工作的


在实践中,它无论如何都会“碰巧起作用”。实现通常不知道是
doStuff
,还是它调用的某些函数,操纵
m\u被取消。因此,它将无法将其保存在寄存器中或跨这些调用的其他地方。

不,他不对-如果没有内存限制,第一个线程可能永远看不到更新。如果使用C++11,则应将
m_isCanceled
声明为
atomic
,或者,如果您不支持,请将其访问与互斥同步。@Andy:对于那些使用旧工具集的人来说,幸运的是,Boost 1.53将包括新的Boost.Atomic库。:-]@ildjarn:很高兴听到,谢谢你分享信息:)你需要在你的
m\u上至少
volatile
被取消
-这将阻止它被缓存在循环中的寄存器中。然而,在某些架构上,这还不够,因为当另一个内核写入变量时,缓存不会更新——在这种情况下,您必须使用原子类型操作。您的第二段不是假定
doStuff()
是不可内联的吗?[我很感激上面的评论说“慢”,这可能意味着复杂且不可内联]。这完全取决于
doStuff
的功能。在从未看到更改的真实平台上编写代码是绝对可能的。doStuff()实际上是对成员变量的方法调用,它执行http请求。它将一组成员变量传递到调用中,但不会被取消。@Bwmat:那么它几乎肯定会“正常工作”。其他线程可以做的任何事情,其中一个函数都可以做,除非实现可以内联整个事情,而实际上,它不能。然而,谁知道下一代更智能的编译器(或需要更多手持才能进行线程同步的硬件)会做什么呢。如果您有原子类型,请使用它们。如果性能不重要,请使用互斥锁。如果失败,请使用<代码> Value,但认为它是一个依赖于平台的优化,而代码<> Value是已知的。事实上,这是一个讨厌的现象,几乎在所有的软件中都能看到。如果doStuff()执行http请求并等待响应,那么在调用cancel()时,直到doStuff()完成后才会执行取消。这完全违背了cancel()的全部目的。当网络断开并且doStuff()挂起直到超时时间到期时会发生什么情况?这个问题困扰着大多数软件!它破坏了可用性。