1

次のコードが与えられます:

...
private static SpinLock logLock = new SpinLock(false);
...

private static void ThreadFunc()
{
    bool lockTaken = false;
    logLock.Enter(ref lockTaken)
    {
        try
        {
            // do stuff with during an acquired SpinLock
        }
        finally
        {
            logLock.Exit();
        }
    }
}

取得中のロックでfalseを受信したためにEnterブロックが「失敗」した場合、現在のスレッドはスピンロックのようにスピンして取得できるようになるまで待機しますか、それともこのブロックが単にバイパスされてそのスレッドが失われますか?

ありがとう、

スコット

4

2 に答える 2

2

SpinLockは、定義上、ブロックではなくロックの取得を待機している間にスレッドをスピンさせます。Enterは、ロックを取得できない場合でも「失敗」せず、待機するだけです。

Enterが例外のスローに失敗する可能性がある唯一のケースは、新しいSpinLock()または新しいSpinLock(true)のいずれかを使用してスレッドの所有権がアクティブ化された場合です。この場合、スレッドがすでに所有しているロックを取得しようとすると、例外がスローされます。あなたの場合、追跡を無効にしてロックを作成したため、これは決して起こり得ません(SpinLock(false))。スレッドがロックを再取得しようとすると、単にデッドロックが発生します。

これについては、SpinLock.Enterメソッドのドキュメントで説明されています。

于 2010-07-05T10:59:13.950 に答える
1

SpinLockは基本的に、変数を特定の値に設定しようとするループです

その実装は次のように考えることができます。

public struct SpinLock
{
    private volatile bool _Locked;

    public void Acquire()
    {
        while (_Locked)
            ;
        _Locked = true;
    }

    public void Release()
    {
        _Locked = false;
    }
}

(もちろん、上記のコードはスレッドセーフではありません。これはクラスのメソッドのシグネチャではないことを私は知っています。それが何をしているのかを示すための単なる擬似コードの変形です)

そうです、SpinLockがすでにロック状態にある場合、それを取得しようとすると、使用可能になるまでスピンします。

また、デフォルトでは(あなたの例のように)、構造体は誰がロックを所有しているかを追跡しないことに注意してください。これは、スレッドがロックを2回取得しようとすると、2回目の試行でそれ自体とデッドロックすることを意味します。

SpinLockの目的は、オーバーヘッドがほとんどないユーザーレベルのロックになることです。GCプレッシャーを追加したり、カーネル同期オブジェクトを割り当てたりすることはありません。これは、いくつかのフィールドを持つ単なる構造体です。

于 2010-07-05T11:06:10.110 に答える