我正在尝试使用Maged M. Michael和Michael L. Scott的算法为并发应用创建一个非阻塞队列包,如here所述。
这需要使用由"sync/atomic"
包提供的原子CompareAndSwap
但是我不确定以下伪代码的Go等价物是什么:
E9: if CAS(&tail.ptr->next, next, <node, next.count+1>)
其中tail
和next
的类型为:
type pointer_t struct {
ptr *node_t
count uint
}
和node
的类型为:
type node_t struct {
value interface{}
next pointer_t
}
如果我理解正确,似乎我需要用结构(指针和uint
)来做CAS。这可能是atomic
- 包吗?
感谢您的帮助!
答案 0 :(得分:10)
如果我理解正确,似乎我需要使用结构(包括&gt;指针和uint)来执行CAS。甚至可以使用原子包吗?
不,那是不可能的。大多数架构仅支持单个单词的原子操作。然而,许多学术论文使用了今天无法获得的更强大的CAS语句(例如比较和交换双重)。幸运的是,在这种情况下通常会使用一些技巧:
例如,您可以从指针中窃取几个位(特别是在64位系统上)并使用它们对您的计数器进行编码。然后你可以简单地使用Go的CompareAndSwapPointer,但是在尝试取消引用之前你需要屏蔽指针的相关位。
另一种可能性是使用指向你的(immutable!)pointer_t结构的指针。无论何时想要修改pointer_t结构中的元素,都必须创建副本,修改副本并原子地替换指向结构的指针。这个成语称为COW(写入时复制),适用于任意大型结构。如果您想使用此技术,则必须将下一个属性更改为next *pointer_t
。
由于教育原因,我最近在Go写了一个无锁列表。您可以在此处找到(imho记录完善的)来源:https://github.com/tux21b/goco/blob/master/list.go
这个相当简短的示例过度使用atomic.CompareAndSwapPointer并且还为标记指针引入了原子类型(MarkAndRef结构)。这种类型与你的pointer_t结构非常相似(除了它存储bool +指针而不是int +指针)。它用于确保在您尝试直接插入元素时未将节点标记为已删除。随意使用此源作为您自己项目的起点。
答案 1 :(得分:0)
您可以这样做:
if atomic.CompareAndSwapPointer(
(*unsafe.Pointer)(unsafe.Pointer(tail.ptr.next)),
unsafe.Pointer(&next),
unsafe.Pointer(&pointer_t{&node, next.count + 1})
)