在 Visual Studio 2019 (16.5) 中查看託管執行緒正在等待的鎖被哪個執行緒佔用

Visual Studio 2019 (16.5) 版本更新中帶來了一項很小很難注意到卻非常實用的功能,查看哪一個託管執行緒正在持有 .NET 對象鎖。

如果你不了解這個功能如何使用,那麼可以閱讀本文。


更新日誌

Visual Studio 的官方更新日誌中對此功能的描述:

View which managed thread is holding a .NET object lock

即「查看託管執行緒正在持有 .NET 對象鎖」。

功能入口

這個功能沒有新的入口,你可以在「調用堆棧」 (Call Stack) 窗口,「並行堆棧」 (Parallel Stacks) 窗口,以及「執行緒」窗口的位置列中查看哪個託管執行緒正在持有 .NET 對象鎖。

Call Stack

示例

現在我們就實際看一下這個功能的用法和效果。於是我寫了一點下面的程式碼。

static void Main(string[] args)  {      var locker = new object();        Thread thread = new Thread(() =>      {          Console.WriteLine("後台執行緒嘗試獲得鎖");          lock (locker)          {              Console.WriteLine("後台執行緒成功獲得鎖");          }      })      {          Name = "walterlv thread",      };        Console.WriteLine("主執行緒嘗試獲得鎖");      Monitor.Enter(locker);      Console.WriteLine("主執行緒成功獲得鎖");        thread.Start();  }

在這段程式碼中,主執行緒獲得鎖之後直接退出,而新執行緒「walterlv thread」則嘗試獲得鎖。

現在在 Visual Studio 2019 中運行這段程式碼,可以看到另一個執行緒是不可能獲得鎖的,於是不會輸出最後那一句,其他都會輸出。

隨後我們在 Visual Studio 中點擊「全部中斷」,也就是那個「暫停」圖標的按鈕。

打開調用堆棧窗口(在「調試 -> 窗口 -> 調用堆棧」),可以看到堆棧最頂端顯示了正在等待鎖,並且指出了執行緒對象。

然後在執行緒窗口(在「調試 -> 窗口 -> 執行緒「)的位置列,滑鼠移上去可以看到與堆棧中相同的資訊。

當然,我們的主執行緒實際上早已直接退出了,所以正在等待的鎖將永遠不會釋放(除非進程退出)。

同樣的資訊,在並行堆棧(在「調試 -> 窗口 -> 並行堆棧」)中也能看到。


參考資料