1

1 つのスレッドが同じスピンロックを 2 回取得しようとすると、デッドロックが発生する理由を説明してもらえますか? (スピンロックが非再帰的であると仮定)

通常のスピンロックの使用法:

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)ただし、2回目の呼び出しでデッドロックが発生する理由がわかりません?

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

上記の関数を使用しようとすると、コードがデッドロックします。これは、スレッドがロックを取得するまで実行を継続しないためです。これは bool を返さないため、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 ループで使用するのにある程度の意味があります。ロックの取得を試みることはできますが、割り当てられた時間内に成功しない場合は、何をすべきかを決めることができます。おそらく、しばらく別の作業を行ってから、ロックの取得を再試行することになるでしょう。

再入可能ではないため、最初に解放せずに同じスレッドがそれを 2 回取得することはできません。このため、コードはデッドロックします。

コードがデッドロックしているように見える最後の例を次に示します。

/** 
* 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 ループを終了します。

于 2013-04-08T04:18:16.040 に答える