在 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 中點擊「全部中斷」,也就是那個「暫停」圖標的按鈕。

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

然後在線程窗口(在「調試 -> 窗口 -> 線程「)的位置列,鼠標移上去可以看到與堆棧中相同的信息。

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

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


參考資料