1

有人可以向我解释为什么当一个线程尝试两次获取同一个自旋锁时会出现死锁吗?(假设自旋锁是非递归的)

常规自旋锁用法:

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)会导致死锁?

4

1 回答 1

4

这个问题似乎真的取决于所讨论的线程库,以及不同函数的规范。所以,让我们考虑几种可能性。

锁定机制可以是阻塞的或非阻塞的,也可以是可重入的和不可重入的。

/** 
* This function performs a busy wait, blocking until it acquires the lock
* This is not re-entrant.
**/
void blocking_acquire_lock(bool thingToLock);

如果你尝试使用前面的函数,你的代码会死锁。这是因为线程在获得锁之前不会继续执行。您不会在 while 循环的条件位置使用它,因为它不返回布尔值。其次,这不是可重入的意思,如果你在同一个线程获得锁后尝试重新获得锁,它会继续等待锁被释放。

/** 
* 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 循环中使用是有意义的。您可以尝试获取锁,但如果在分配的时间内没有成功,您可以决定做什么。也许,您会决定在其他事情上工作一段时间,然后重新尝试获取锁。

由于它不是可重入的,它不会允许同一个线程在没有先释放的情况下两次获取它。因此,您的代码将死锁。

Here is one last example which will seem to deadlock on your code.

/** 
* 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);

This lock is re-entrant, so if a thread owns the lock, it can re-acquire it. However, if you use this inside of a while loop like the following, you will notice something interesting.

my_lock = false; 
while(acquiring_lock(my_lock, 1000)) { ; }
    ....critical section....
release_lock(lock);  

Since the lock returns true if it acquires the lock within 1 second, and this is the only thread, it should likely acquire the lock without problem. It returns true. In which case, it will stay in the while loop. The while loop is empty, so it immediately tries re-acquiring the lock.

Since it is re-entrant, I would expect it to continually succeed. It will continue to successfully re-acquire the lock, and never get past the while loop.

I would expect the following code with an extra "!" to be what you intended.

my_lock = false; 
while( !acquiring_lock(my_lock, 1000)) { ; }
    ....critical section....
release_lock(lock);  

This version, will actually stop trying to acquire the lock, i.e. exit the while loop, once it has acquired the lock.

于 2013-04-08T04:18:16.040 回答