竞争原子操作可以相互挨饿吗?

时间:2010-02-07 00:23:18

标签: c++ multithreading atomic lock-free compare-and-swap

想象一下有两个线程的程序。他们正在运行以下代码(CAS引用Compare and Swap):

// Visible to both threads
static int test;

// Run by thread A
void foo()
{
    // Check if value is 'test' and swap in 0xdeadbeef
    while(!CAS(&test, test, 0xdeadbeef)) {}
}

// Run by thread B
void bar()
{
    while(1) {
        // Perpetually atomically write rand() into the test variable
        atomic_write(&test, rand());
    }
}

线程B是否有可能永远导致线程A的CAS失败,从而永远不会将0xdeadbeef写入'test'?或者自然调度抖动是否意味着在实践中这种情况永远不会发生?如果在线程A的while循环中完成了一些工作会怎样?

2 个答案:

答案 0 :(得分:6)

作为一个理论问题,是的。如果你能以某种方式管理这两个线程像这样的

锁步运行
    time     thread A     thread B
    ----     --------     --------
     ||       CAS
     ||                   atomic_write
     ||       CAS
     \/                   atomic_write

然后CAS永远不会返回true。

实际上,当线程共享CPU / Core时,永远不会发生这种情况,并且当线程在不同的CPU或内核上运行时,不太可能发生这种情况。在实践中,令人难以置信地不可能发生超过几个周期,并且天文学上不太可能发生超过调度程序量子。

这就是这个代码

void foo()
{
    // Check if value is 'test' and swap in 0xdeadbeef
    while(!CAS(&test, test, 0xdeadbeef)) {}
}

执行它的操作,即获取test的当前值,并将其与test进行比较以查看它是否已更改。在现实世界中,CAS的迭代将由执行实际工作的代码分开。需要volatile关键字来确保编译器在调用CAS之前获取测试,而不是假设它可能仍然存在于寄存器中的副本仍然有效。

或者您要测试的值不是test的当前值,而是某种最后已知的值。

换句话说,这个代码示例是对该理论的测试,但是你不会在实践中使用这样的CAS,所以即使你可以让它失败,它也不一定告诉你它是如何失败的当用于现实世界的算法时。

答案 1 :(得分:2)

在这种情况下肯定会发生饥饿。引用the wikipedia page

  

它也被证明了   广泛可用的原子条件   原语,CAS和LL / SC,不能   提供无饥饿   许多常见数据的实现   没有记忆成本的结构   数量呈线性增长   线程。无等待算法   因此在研究和研究方面都很少见   在实践中。

(请参阅相关页面中的链接以获取数学证明)。