我正在寫一個廣泛使用多線程的應用程序。一些線程使用ReaderWriterLockSlim共享一個observablecollection。如何知道誰擁有ReaderWriterLockSlim?
我不時有一個死鎖,我需要知道哪個線程在死鎖時刻持有鎖。我怎麼知道這個?我看過對象的屬性,沒有什麼明顯的。目前我所知道的是哪些線程正在等待鎖定。
感謝您的幫助!
編輯:當然,我正在談論的是在調試時找到它,並提供所有調試信息。
我正在寫一個廣泛使用多線程的應用程序。一些線程使用ReaderWriterLockSlim共享一個observablecollection。如何知道誰擁有ReaderWriterLockSlim?
我不時有一個死鎖,我需要知道哪個線程在死鎖時刻持有鎖。我怎麼知道這個?我看過對象的屬性,沒有什麼明顯的。目前我所知道的是哪些線程正在等待鎖定。
感謝您的幫助!
編輯:當然,我正在談論的是在調試時找到它,並提供所有調試信息。
在死鎖過程中,只需看一下線程調試面板中的當前線程,通過調用堆棧就可以找出哪個線程獲取了鎖。
如果您需要知道代碼中的線程ID,您可以隨時將其保存爲靜態,或從readerwriterlockslim繼承並添加線程屬性。
您可以隨時嘗試追蹤鎖之前和之後的線程ID,以便您已經記錄了發生了什麼以及鎖定了什麼時間以及何時鎖定了它。您可以寫入一個文件或只需在調試器輸出窗口中查看所有的跟蹤。 我相信你可以使用跟蹤斷點(Breakpoint - > When Hit ...)而不是真正的跟蹤代碼來在輸出窗口中快速顯示某些內容。
ReaderWriterLockSlim
沒有密封,所以你可以繼承它並附上你需要的任何信息。問題是有用的方法不是虛擬的,所以你不能覆蓋它們。但是,除了捕獲調用方法的線程之外,您還可以添加自己的方法,如EnterReadLockDebug
和ExitReadLockDebug
等,它們在幕後調用EnterReadLock
和ExitReadLock
。這不是一個很好的解決方案,因爲您必須更改所有呼叫站點。但是,如果使用調試器太麻煩,那麼這可能是一個合理的選擇。
使用條件編譯的主題有很多變體。您可以檢測到Debug版本和Release版本,並根據哪個構建配置處於活動狀態注入必要的調試邏輯。當調試處於活動狀態時注入調試信息,當釋放處於活動狀態時將其省略。
這是我結束,以供將來參考代碼:
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
}
}
這裏是我的意思。
只需跟蹤鎖定並解鎖,當您遇到死鎖時,系統將停止工作,最後一個「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();
}
}
}
我有20到30個線程之間的東西。拿線程的人可能是用了很遠的方法做的,所以看看調用堆棧是不夠的,我希望readerwriterlock已經有一個屬性表示當前所有者。 –
我想我會像你說的那樣創建一個後代... –
如果你有20或30個線程,那麼每個線程都可能比較麻煩。然而,如果你說你死鎖了,所以很可能你會看到所有的線程都在同一個位置等待,一個線程正在等待「調用」等等。只需快速查看線程面板中的「位置列」即可。 –