我一直在思考如何实现一个无锁单链表。老实说,我没有看到很多防弹的方法来做到这一点。即使是使用的更强大的方法最终也存在CAS
一定程度的ABA 问题。
所以我开始思考。部分无锁系统不会比总是使用锁更好吗?某些操作可以是原子的和无锁的吗?如果我能做到这一点,它应该仍然是线程安全的。
所以,直奔问题。我正在考虑一个简单的单链表。2 主要业务。 push
和pop
。push
总是在前面插入。像这样的东西:
void push(int n) {
T *p = new T;
p->n = n;
p->next = root;
root = p;
}
而 pop 总是采用第一个元素。像这样的东西:
T *pop() {
T *p = root;
root = root->next;
return p;
}
显然,push 并不简单,简单的无锁方法可能不会发生。但流行看起来可能是可行的。使用 gcc-intrinsics 我想到了这个:
T *pop() {
return __sync_lock_test_and_set(&root, root->next);
}
功能等同?对。无锁?对。线程安全?我不知道。我的直觉反应是否定的,这就是为什么。
我担心其中一个参数test_and_set
必须取消引用内存。如果 root 在root->next
和对 的调用之间发生变化怎么办__sync_lock_test_and_set
?
我想这段代码等价于:
T *pop() {
T *temp = root->next;
// are we broken if a push/pop happens here?
return __sync_lock_test_and_set(&root, temp);
}
所以,就像我说的,我认为这段代码是不正确的。但是任何人都可以肯定地说我得出了正确的结论(我不想注销一些效果很好的东西)。如果它真的像我怀疑的那样坏了。有没有简单的解决方案?