有人可以向我解释为什么当一个线程试图抓住两次相同的自旋锁时会出现死锁吗? (假设自旋锁是非递归的)
常规螺旋锁使用:
lock = false;
while(acquiring_lock(lock)) {} //sit in the loop and wait for lock to become available
....critical section....
release_lock(lock);
但是,我不明白为什么第二次调用acquiring_lock(lock)
会导致死锁?
答案 0 :(得分:3)
看起来这个问题确实取决于有问题的线程库,以及不同功能的规范。所以,让我们考虑一些可能性。
锁定机制可能是blocking或非阻止以及re-entrant,也不是可重入的。
/**
* This function performs a busy wait, blocking until it acquires the lock
* This is not re-entrant.
**/
void blocking_acquire_lock(bool thingToLock);
如果您尝试使用上述功能,您的代码将会死锁。这是因为线程在获得锁之前不会继续执行。你不会在while循环的条件位置使用它,因为它不返回bool。其次,它是不可重复的意思,如果你尝试在获得锁之后即使使用相同的线程重新获取锁,它将继续等待锁被释放。
/**
* This function performs a non-blocking busy wait, blocking for up to X milleseconds,
* until it acquires the lock. This is not re-entrant.
* returns true if lock acquired, false if lock not acquired
**/
bool non_blocking_acquire_lock(bool thingToLock, int timeoutInMilliseconds);
这个版本在while循环中使用是有意义的。您可以尝试获取锁定,但如果在指定的时间内没有成功,您可以决定该怎么做。也许,你会决定暂时处理其他事情,然后重新尝试获取锁定。
由于它不是可重入的,因此它不会允许同一个线程两次获取它,而不会先释放它。因此,您的代码将陷入僵局。
这是最后一个似乎在您的代码上死锁的示例。
/**
* This function performs a non-blocking busy wait, blocking for up to X milleseconds,
* until it acquires the lock. This is re-entrant.
* returns true if lock acquired, false if lock not acquired
**/
bool non_blocking_reentrant_acquire_lock(bool thingToLock, int timeoutInMilliseconds);
此锁是可重入的,因此如果某个线程拥有该锁,则可以重新获取该锁。但是,如果你在while循环中使用它,如下所示,你会注意到一些有趣的东西。
my_lock = false;
while(acquiring_lock(my_lock, 1000)) { ; }
....critical section....
release_lock(lock);
由于如果锁在1秒内获得锁定,则锁定返回true,并且这是唯一的线程,它应该可以获得锁定而不会出现问题。它返回true。在这种情况下,它将保持在while循环中。 while循环为空,因此它会立即尝试重新获取锁定。
由于它是可重入的,我希望它能够不断取得成功。它将继续成功地重新获得锁定,并且永远不会超过while循环。
我希望以下代码带有额外的“!”成为你的意图。
my_lock = false;
while( !acquiring_lock(my_lock, 1000)) { ; }
....critical section....
release_lock(lock);
这个版本实际上会在获得锁定后停止尝试获取锁定,即退出while循环。