1

単体テストを書いているときに、ReaderWriterLock に関する非常に奇妙な問題に遭遇しました。タイムアウト オプションを 50 ミリ秒に設定して UpgradeToWriterLock メソッドをテストしてみました。

メイン スレッドでリーダー ロックを取得し、多数のタスクを開始します。タスクでは、リーダー ロックも取得してから、タイムアウトを使用してライターにアップグレードしようとします。メインスレッドが読み取りロックを保持しているため、これはすべてのスレッドで失敗するはずです。タイムアウトは 50 ミリ秒であるため、タスクはタイムアウト例外をスローして終了する必要があります。10 を超えるタスクを開始すると、開始されません。UpgradeToWriterLock でスタックします。

誰でも説明できますか?以下ソースコード全文。

    [TestMethod]
    public void UpgradeLockFailTest()
    {
        // strangely when more than 10 threads then it gets stuck on UpgradeToWriterLock regardless of the timeout
        const int THREADS_COUNT = 20;
        // 50 milliseconds
        const int TIMEOUT = 50;

        // create the main reader writer lock
        ReaderWriterLock rwl = new ReaderWriterLock();

        // acquire the reader lock on the main thread
        rwl.AcquireReaderLock(TIMEOUT);

        // create and start all the tasks
        Task[] tasks = new Task[THREADS_COUNT];
        for (int i = 0; i < THREADS_COUNT; i++)
        {
            tasks[i] = Task.Factory.StartNew(() =>
            {
                try
                {
                    // acquire the reader lock on the worker thread
                    rwl.AcquireReaderLock(TIMEOUT);

                    // acquire the writer lock on the worker thread 
                    rwl.UpgradeToWriterLock(TIMEOUT); // <-- GETS STUCK HERE AND DOESN'T RESPECT TIMEOUT

                }
                finally
                {
                    rwl.ReleaseLock();
                }

            });
        }

        // should be enough for all the tasks to be created
        Thread.Sleep(2000);

        try
        {
            // wait for all tasks
            Task.WaitAll(tasks); // <-- GETS STUCK HERE BECAUSE THE TASKS ARE STUCK ON UpgradeToWriterLock
        }
        catch (AggregateException ae)
        {
            Assert.AreEqual(THREADS_COUNT, ae.InnerExceptions.Count);
        }

        // release all the locks on the main thread
        rwl.ReleaseLock();
    }

興味深いのは、タスクを待機する前にメイン スレッド リーダー ロックを解放すると、すべてが期待どおりに機能することです。正しい数のタイムアウト例外がスローされます。

4

1 に答える 1

4

最後の 1 つだけでなく、それらすべてが動かなくなってしまいますか?

UpgradeToWriterLockドキュメントから:

UpgradeToWriterLock メソッドを呼び出したスレッドがリーダー ロックを再取得できるようになるまで、タイムアウト例外はスローされません。ライター ロックを待機しているスレッドが他にない場合、これはすぐに行われます。ただし、別のスレッドがライター ロックのキューに入れられている場合、UpgradeToWriterLock メソッドを呼び出したスレッドは、現在のすべてのリーダーがロックを解放し、1 つのスレッドがライター ロックを取得して解放するまで、リーダー ロックを再取得できません。これは、現在のスレッドが UpgradeToWriterLock メソッドを呼び出した後に、ライター ロックを要求した他のスレッドがそれを要求した場合でも当てはまります。

タイムアウト例外がスローされるには、複数の条件が発生する必要があることに注意してください。「別のスレッドがライター ロックのキューに入れられている場合、UpgradeToWriterLock メソッドを呼び出したスレッドは、それまでリーダー ロックを再取得できず、[例外をスロー] できません」:

  1. 現在のすべてのリーダーがロックを解除しました
  2. 1 つのスレッドがライター ロックを取得して解放しました

アップグレードを試行する最後のスレッドでこれらの状態が発生することを決して許可しないため、 で永遠に待機し、これも永遠にUpgradeToWriterLock待機しWaitAllます。待機する前にメインスレッドもアップグレードしようとした場合は、問題ないと思います。

于 2014-05-23T18:25:39.070 に答える