【问题标题】:How to know who owns a ReaderWriterLockSlim?如何知道谁拥有 ReaderWriterLockSlim?
【发布时间】:2012-05-23 20:21:28
【问题描述】:

我正在编写一个广泛使用多线程的应用程序。一些线程使用 ReaderWriterLockSlim 共享一个 observablecollection。

我不时遇到死锁,我需要知道在死锁时哪个线程持有锁。我怎么知道这个?我查看了对象属性,没有明显的东西。目前我只知道哪些线程正在等待锁。

感谢您的帮助!

编辑:当然,我说的是在调试时找到它,并提供所有可用的调试信息。

【问题讨论】:

    标签: c# .net multithreading deadlock readerwriterlockslim


    【解决方案1】:

    在死锁期间,只需查看线程调试面板中的当前线程,查看您的调用堆栈,您就会发现哪个线程获得了锁。

    如果您需要知道代码中的线程id,可以随时静态保存,或者从readerwriterlockslim继承并添加线程属性。

    【讨论】:

    • 我有 20 到 30 个线程。占用线程的那个可能是在一个很远的方法中完成的,所以只看调用堆栈是不够的,我希望 readerwriterlock 已经有一个指示当前所有者的属性。
    • 如果你有 20 或 30 个线程,那么绕着每个线程走可能会很乏味。但是,如果你说你死锁了,那么你很可能会看到所有线程都在同一个位置等待,而一个线程正在等待“调用”等。只需快速查看线程面板中的“位置列”即可。
    • 创建后代,但在解决死锁后,将其替换为原来的超薄储物柜。
    • 不幸的是,他们做的事情完全不同,我通常有 2 个线程在等待,另一个将这些线程死锁......在另外 15 个线程的中间......:S 无论如何,我可以用后代做工作。谢谢。
    【解决方案2】:

    这就是我的意思。
    只需跟踪锁定和解锁,当您遇到死锁时,系统将停止,最后一个“Enter”将指向锁定线程的方向。

    public class ReaderWriterLockSlimExtended : ReaderWriterLockSlim
    {
        private Thread m_currentOwnerThread = null;
        private object m_syncRoot = new object();
    
        public Thread CurrentOwnerThread
        {
            get
            {
                lock (m_syncRoot)
                {
                    return m_currentOwnerThread;
                }
            }
        }
    
        public Thread CurrentOwnerThreadUnsafe
        {
            get
            {
                return m_currentOwnerThread;
            }
        }
    
        public new void EnterWriteLock()
        {
            lock (m_syncRoot)
            {
                base.EnterWriteLock();
                m_currentOwnerThread = Thread.CurrentThread;
            }
            Debug.WriteLine("Enter Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
        }
    
        public new void ExitWriteLock()
        {
            Debug.WriteLine("Exit Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
            lock (m_syncRoot)
            {
                m_currentOwnerThread = null; //Must be null before exit!
                base.ExitWriteLock();
            }
        }  
    }
    

    【讨论】:

      【解决方案3】:

      您总是可以尝试在锁定之前和之后跟踪线程 ID,这样您就可以记录发生了什么以及谁锁定了它以及何时锁定。您可以写入文件或仅检查调试器输出窗口以查看所有跟踪。 我相信您可以使用跟踪断点 (Breakpoint -> When Hit...) 而不是真正的跟踪代码来在输出窗口中快速获取一些东西。

      【讨论】:

        【解决方案4】:

        ReaderWriterLockSlim 未密封,因此您可以将其子类化并以这种方式附加您需要的任何信息。问题是有用的方法不是虚拟的,所以你不能覆盖它们。但是,除了捕获调用该方法的线程之外,您还可以添加自己的方法,例如 EnterReadLockDebugExitReadLockDebug 等,它们在后台调用 EnterReadLockExitReadLock。这不是一个很好的解决方案,因为您必须更改所有呼叫站点。但是,如果使用调试器太麻烦,那么这可能是一个合理的选择。

        使用条件编译的主题有很多变化。您可以检测 Debug vs. Release 构建,并根据激活的构建配置注入必要的调试逻辑。 Debug 激活时注入调试信息,Release 激活时省略。

        【讨论】:

          【解决方案5】:

          这是我结束的代码,以供将来参考:

          using System;
          using System.Threading;
          
          namespace Utils
          {
          public class ReaderWriterLockSlim2
          {
              #region Attributes
          
              private readonly TimeSpan _maxWait;
              private readonly ReaderWriterLockSlim _lock;
          
              #endregion
          
              #region Properties
          
              public int CurrentWriteOwnerId { get; private set; }
              public string CurrentWriteOwnerName { get; private set; }
          
              #endregion
          
              #region Public Methods
          
              public ReaderWriterLockSlim2(LockRecursionPolicy policy, TimeSpan maxWait)
              {
                  _maxWait = maxWait;
                  _lock = new ReaderWriterLockSlim(policy);
              }
          
              public void EnterWriteLock()
              {
                  if (!_lock.TryEnterWriteLock(_maxWait))
                  {
                      throw new TimeoutException(string.Format("Timeout while waiting to enter a WriteLock. Lock adquired by Id {0} - Name {1}", this.CurrentWriteOwnerId, this.CurrentWriteOwnerName));
                  }
                  else
                  {
                      this.CurrentWriteOwnerId = Thread.CurrentThread.ManagedThreadId;
                      this.CurrentWriteOwnerName = Thread.CurrentThread.Name; 
                  }
              }
          
              public void ExitWriteLock()
              {
                  _lock.ExitWriteLock();
                  this.CurrentWriteOwnerId = 0;
                  this.CurrentWriteOwnerName = null;  
              }
          
              public void EnterReadLock()
              {
                  _lock.EnterReadLock();
              }
          
              public void ExitReadLock()
              {
                  _lock.ExitReadLock();
              }
          
              #endregion
          }
          }
          

          【讨论】:

            猜你喜欢
            • 2010-11-06
            • 1970-01-01
            • 2011-06-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-27
            • 2014-06-17
            • 2018-07-08
            相关资源
            最近更新 更多