ReaderWriterLock.UpgradeToWriterLock在超时后不会抛出异常?

时间:2014-05-23 17:28:46

标签: c# .net multithreading readerwriterlock

在编写单元测试时,我偶然发现了一个与ReaderWriterLock相关的奇怪问题。 我尝试使用设置为50毫秒的超时选项测试UpgradeToWriterLock方法。

在主线程上,我将读取器锁定,然后启动大量任务。在任务上,我也将读取器锁定,然后尝试在超时时升级到写入器。由于主线程正在保持读锁定,因此每个都应该失败。由于timout是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();
    }

有趣的是,如果我在等待任务之前释放主线程读取器锁,一切都按预期工作。抛出正确的超时异常数。

1 个答案:

答案 0 :(得分:4)

你确定它们都被卡住了,而不仅仅是最后一个吗?

来自UpgradeToWriterLock documentation

  

在调用UpgradeToWriterLock方法的线程可以重新获取读取器锁之前,不会抛出超时异常。如果没有其他线程等待写入程序锁定,则立即发生这种情况。 但是,如果另一个线程排队等待编写器锁定,则调用UpgradeToWriterLock方法的线程无法重新获取读取器锁定,直到所有当前读取器都已释放其锁定,并且一个线程已获取并释放写入器锁定。即使请求编写器锁的其他线程在当前线程调用UpgradeToWriterLock方法之后请求它,也是如此。

请注意要抛出超时异常必须发生的多个条件。 “如果另一个线程排队等待编写器锁定,则调用UpgradeToWriterLock方法的线程无法重新获取读取器锁定[并抛出异常]直到”:

  1. 目前所有读者都已发布锁定
  2. 一个线程获得并释放了作者锁
  3. 您永远不会允许最后一个尝试升级的线程发生这些情况,因此您永远等待UpgradeToWriterLock,因此WaitAll也会永远等待。如果您的主线程在等待之前也尝试升级,我认为您没问题。