想象一下有两个线程的程序。他们正在运行以下代码(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循环中完成了一些工作会怎样?
答案 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)
它也被证明了 广泛可用的原子条件 原语,CAS和LL / SC,不能 提供无饥饿 许多常见数据的实现 没有记忆成本的结构 数量呈线性增长 线程。无等待算法 因此在研究和研究方面都很少见 在实践中。
(请参阅相关页面中的链接以获取数学证明)。