我正在努力了解如何在锁实现中使用fetch和add(原子操作)。
我在维基百科上看到了这篇文章,我发现它至少在另一个地方有重复。这个实现没有意义,在我看来有一个或更多的错误。当然,我可能错过了一个微妙的点,也没有真正理解所描述的内容。
发件人https://en.wikipedia.org/wiki/Fetch-and-add
<< atomic >>
function FetchAndAdd(address location, int inc) {
int value := *location
*location := value + inc
return value
}
record locktype {
int ticketnumber
int turn
}
procedure LockInit( locktype* lock ) {
lock.ticketnumber := 0
lock.turn := 0
}
procedure Lock( locktype* lock ) {
int myturn := FetchAndIncrement( &lock.ticketnumber ) //must be atomic, since many threads might ask for a lock at the same time
while lock.turn ≠ myturn
skip // spin until lock is acquired
}
procedure UnLock( locktype* lock ) {
FetchAndIncrement( &lock.turn ) //this need not be atomic, since only the possessor of the lock will execute this
}
根据文章,他们首先做LockInit。FetchAndIncrement调用FetchAndAdd,inc设置为1。
如果这不包含一个错误,我不明白它怎么可能工作。
第一个访问它的线程将获得它:
lock.ticketnumber=1lock.turn=0。
比方说,在锁被释放之前,还会发生5次对锁的访问。
lock.ticketnumber=6lock.turn=0
第一个线程释放锁。
lock.ticketnumber=6lock.turn=1
下一个线程进入,状态为
lock.ticketnumber=7lock.turn=1
返回值:myturn=6(faa之前的lock.ticketnumber)。
在这种情况下:
而lock.turn≠myturn
不可能是真的。
这幅插图中有错误吗?还是我遗漏了什么?
如果这个实现中有一个bug,该怎么修复呢?
Thanx
Julian
该死,我现在看到了。我发现它指的是算法的一般描述,然后我更仔细地看了看。
当一个线程调用Lock时,它会旋转等待返回的值,出于某种原因,我认为它一直在调用那个函数。
当它旋转时,它会等待,直到另一个线程增加匝数,并最终成为myturn的数目。
很抱歉浪费了你的时间。
https://en.wikipedia.org/wiki/Ticket_lock