我正在编写一个广泛使用多线程的应用程序。一些线程使用ReaderWriterLockSlim共享一个observablecollection。
我不时遇到死锁,我需要知道哪一个是在死锁时刻持有锁的线程。我怎么知道这个?我看过对象属性,没有什么明显的。目前我所知道的是哪些线程正在等待锁定。
感谢您的帮助!
编辑:我当然是在讨论在调试时找到它并提供所有可用的调试信息。
答案 0 :(得分:3)
在你的死锁期间,只需查看线程调试面板中的当前线程,查看你的调用堆栈,你就会发现哪个线程已经锁定了。
如果您需要知道代码中的线程ID,您可以始终静态保存它,或者从readerwriterlockslim继承并添加线程属性。
答案 1 :(得分:2)
您总是可以尝试在锁定之前和之后跟踪线程ID,因此您已经记录了发生的事情以及锁定它的时间和时间。您可以写入文件或只是检查调试器输出窗口以查看所有跟踪。 我相信你可以使用跟踪断点(Breakpoint - > When Hit ...)而不是真实的跟踪代码来在输出窗口中快速输入内容。
答案 2 :(得分:2)
ReaderWriterLockSlim
未密封,因此您可以将其子类化并附加您需要的任何信息。问题是有用的方法不是虚拟的,所以你不能覆盖它们。但是,除了捕获方法所在的线程之外,您还可以添加自己的方法,如EnterReadLockDebug
和ExitReadLockDebug
等在幕后调用EnterReadLock
和ExitReadLock
的方法。调用。这不是一个很好的解决方案,因为您必须更改所有呼叫站点。但是,如果使用调试器太麻烦,那么这可能是一个合理的选择。
使用条件编译主题有很多变化。您可以检测Debug与Release版本,并根据活动的构建配置注入必要的调试逻辑。在Debug处于活动状态时注入调试信息,并在Release处于活动状态时省略它。
答案 3 :(得分: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();
}
}
}
答案 4 :(得分:0)
这是我结束的代码,供将来参考:
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
}
}