Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# readerwriterlock是否允许在获取写锁时进行读取?_C#_Multithreading - Fatal编程技术网

C# readerwriterlock是否允许在获取写锁时进行读取?

C# readerwriterlock是否允许在获取写锁时进行读取?,c#,multithreading,C#,Multithreading,我有一个静态类,它由多个远程处理和应用程序线程的其他内部线程访问。这个类的部分功能是控制对各种文件的读/写访问,因此我在文件列表上实现了一个静态ReaderWriterLock。该项目使用.net framework 2.0作为客户需求的一部分 但是,当我使用多个不同的客户端(通常我使用16个)对系统进行压力测试时,每个客户端都会执行大量的读写操作,然后是非常间歇性的,只有在几个小时甚至几天之后,至少完成了500k+事务,系统才会崩溃。好的,我们有一个bug 但是,当我检查所有锁定事件的日志时,

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

但是,当我使用多个不同的客户端(通常我使用16个)对系统进行压力测试时,每个客户端都会执行大量的读写操作,然后是非常间歇性的,只有在几个小时甚至几天之后,至少完成了500k+事务,系统才会崩溃。好的,我们有一个bug

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

1:线程A直接获取写锁,检查IsWriterLock会显示为true

2:线程B尝试获取读卡器锁并且成功,即使线程a仍然具有写锁

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
如果是MSDN,则不可能同时保持读写器锁。 由于其他原因,在您的过程中是否可能在任何时候拥有2个readerWriterLock对象

另一件奇怪的事情是,使用iswriterlockhold调试线程,而当前线程是reader线程,不允许您了解在另一个线程中编写。 您如何知道线程A仍然持有写入程序锁,以及如何知道不是调试日志系统延迟或“混合”线程给出的指令

另一种想法是,其他资源共享是否可能导致死锁?那会导致崩溃吗?同时,空异常仍然是奇怪的,除非在哪里考虑死锁清除和READ RealWreBoice复位。 你的问题很奇怪,真的

还有一个问题,这并不能解决您的问题。您使用isTaken做什么,而在调试应用程序时,您依赖于ISWriterLockHold(或ISReaderLockHold)?
为什么不在finally block中使用它呢?

@All终于找到了这个问题的解决方案。@Yannick您走对了方向

如果MSDN说不可能同时持有读写器锁

今天,我从微软得到确认,如果多处理器系统的负载非常重(注意:我永远不会在AMD系统上只在Intel上重现这个问题)ReaderWriterLock类对象可能会损坏,如果在任何给定阶段写入程序的数量增加,则这种情况的风险会增加,因为写入程序可以在队列中备份


在过去的两周里,我一直在使用.Net 3.5 ReaderWriterLockSlim类运行,但没有遇到此问题,这与Microsoft已确认的ReaderWriterLockSlim类没有与fat ReaderWriterLock类相同的损坏风险相对应。

要完成此操作,是否可以添加IsTaken=true语句?我不知道它是否解释了问题,但代码显然是错误的;发布必须是first try/finally的一部分-否则实际工作代码中的任何异常都将导致锁无法释放。Marc-我不确定我是否同意你的说法。如果工作代码中抛出任何异常,那么必须始终在t之前调用finally方法应用程序或线程终止。因此应始终释放锁。@JohnV2020-根据您的代码,似乎您在try-finally之外“做了一些工作”,因为注释在try-finally之外。我假设您的意思是您在try块内做工作。正确-工作在try/finally块内执行