readerwriterlock允许读取写入锁定获取?

时间:2011-04-25 10:54:10

标签: c# multithreading

我有一个静态类,可以通过多个远程处理和应用程序线程的内部访问。该类的部分功能是控制对各种文件的读/写访问,因此我在文件列表上实现了静态ReaderWriterLock。该项目使用.net框架2.0作为客户要求的一部分。

然而,当我使用许多不同的客户端(通常我使用16个)对系统进行压力测试时,每个客户端执行大量的读写操作,然后非常间歇性地进行,并且仅在经过几个小时甚至几天后至少达到500k +交易完成了系统崩溃。好的,我们有一个错误..

但是当我检查所有锁定事件的日志时,我可以看到发生了以下情况:

1:线程A直接获取写锁,检查IsWriterLock是否为真。

2:即使线程A仍然具有写锁定,线程B也会尝试获取读取器锁定并成功

3:系统现在崩溃,堆栈跟踪现在向readerwriterlock显示空引用异常

此过程之前已经运行了数十万次,没有任何错误,我可以检查日志,看看在所有情况下读取锁被阻止,直到写入退出。我也尝试将readerwriterlock实现为单例,但问题仍然存在

有没有人见过这样的事情?

使用的readerwriterlock实现的简化版本如下所示:

private const int readwriterlocktimeoutms = 5000;
    private static ReaderWriterLock readerWriterLock = new ReaderWriterLock();


    // this method will be called by thread A
    public static void MethodA()
    {
        // bool to indicate that we have the lock
        bool IsTaken = false;

        try
        {                
            // get the lock
            readerWriterLock.AcquireWriterLock(readwriterlocktimeoutms);

            // log that we have the lock for debug
            // Logger.LogInfo("MethodA: acquired write lock; writer lock held {0}; reader lock held {1}", readerWriterLock.IsWriterLockHeld.ToString(),readerWriterLock.IsReaderLockHeld.ToString(), );

            // mark that we have taken the lock
            IsTaken = true;
        }
        catch(Exception e)
        {
            throw new Exception(string.Format("Error getting lock {0} {1}", e.Message, Environment.StackTrace));
        }

        try
        {
           // do some work
        }
        finally
        {
            if (IsTaken)
            {
                readerWriterLock.ReleaseWriterLock();
            }
        }

    }

    // this method will be called by thread B
    public static void MethodB()
    {
        // bool to indicate that we have the lock
        bool IsTaken = false;

        try
        {
            // get the lock
            readerWriterLock.AcquireReaderLock(readwriterlocktimeoutms);

            // log that we have the lock for debug
            // Logger.LogInfo("MethodB: acquired read lock; writer lock held {0}; reader lock held {1}", readerWriterLock.IsWriterLockHeld.ToString(),readerWriterLock.IsReaderLockHeld.ToString(), );

            // mark that we have taken the lock
            IsTaken = true;
        }
        catch (Exception e)
        {
            throw new Exception(string.Format("Error getting lock {0} {1}", e.Message, Environment.StackTrace));
        }

        try
        {
           // do some work
        }
        finally
        {
            if (IsTaken)
            {
                readerWriterLock.ReleaseReaderLock();
            }
        }
    }

enter code here

2 个答案:

答案 0 :(得分:7)

@All终于有了解决这个问题的方法。 @Yannick你走在正确的轨道上......

如果MSDN说不可能同时保持读写器锁定。

今天我得到了微软的确认,在多处理器系统负载非常繁重的情况下(注意:我永远无法在AMD系统上仅在英特尔上重现这个问题),这可能导致ReaderWriterLock类对象被破坏,这样做的风险如果任何给定阶段的编写者的数量增加,因为这些可以在队列中备份。

在过去的两周里,我一直在使用.Net 3.5 ReaderWriterLockSlim类运行并且没有遇到过这个问题,这与微软已经确认readerwriterlockslim类与fatWat ReaderWriterLock具有相同的损坏风险相对应。类。

答案 1 :(得分:3)

如果MSDN says that ,则无法同时保持读写器锁定。 由于其他原因,您的过程中是否有可能随时拥有2个readerWriterLock对象?

另一个奇怪的是,使用isWriterLockHeld调试一个线程,而当前线程是一个读者,不允许你知道在另一个线程中写入。 你怎么知道线程A仍然保持一个写入器锁,你怎么知道它不是调试日志系统延迟或“混合”线程给出的指令?

其他想法,共享的其他资源是否可能导致死锁?这会以某种方式导致崩溃? (虽然Null Exception仍然很奇怪,除非考虑清除死锁和readerWriterLock重置。

你的问题很奇怪,是的。

还有其他问题,这不会解决你的问题。您使用的是什么,而在调试您的应用程序时,您依赖isWriterLockHeld(或isReaderLockHeld)? 为什么不在你的finally块中使用它?