2010-11-10 138 views
7

我的應用程序中有一個錯誤,只有當我在調試器中暫停應用程序幾分鐘時纔會顯示它的面部。我懷疑這是由於我使用的第三方網絡庫有一個心跳線程,當它在心跳線程暫停時無法ping服務器時,它會斷開連接。在運行時暫停當前進程中的所有線程

我想寫一個測試用例應用程序來驗證這是錯誤的原因。爲此,我需要一種方法來暫停應用程序中的所有線程(我將稍後縮小爲僅暫停我懷疑可能是心跳線程的線程)以模擬暫停調試器中的應用程序。

有誰知道如何做到這一點?一個線程甚至有可能導致另一個線程進入睡眠狀態?

謝謝, 亞歷克斯

UPDATE:

我最終決定,我並不真的需要一個應用程序爲我做到這一點,看到的一點是,只是爲了驗證,暫停在調試器正在導致斷開連接。所以,在這裏就是我所做的。(最簡單的方法往往是最好的......或者至少是最簡單的...)

private static void Main(string[] args) 
    { 
     IPubSubAdapter adapter = BuildAdapter(); 
     bool waitingForMessage; 
     adapter.Subscribe(_topic, message => waitingForMessage = false, DestinationType.Topic); 
     Stopwatch timePaused = new Stopwatch(); 
     while (adapter.IsConnected) 
     { 
      Console.WriteLine("Adapter is still connected"); 
      waitingForMessage = true; 
      adapter.Publish(_topic, "testmessage", DestinationType.Topic); 
      while (waitingForMessage) 
      { 
       Thread.Sleep(100); 
      } 
      timePaused.Reset(); 
      timePaused.Start(); 
      Debugger.Break(); 
      timePaused.Stop(); 
      Console.WriteLine("Paused for " + timePaused.ElapsedMilliseconds + "ms."); 
      Thread.Sleep(5000); // Give it a chance to realise it's disconnected. 
     } 
     Console.WriteLine("Adapter is disconnected!"); 
     Console.ReadLine(); 
    } 

和輸出:

Adapter is still connected 
Paused for 10725ms. 
Adapter is still connected 
Paused for 13298ms. 
Adapter is still connected 
Paused for 32005ms. 
Adapter is still connected 
Paused for 59268ms. 
Adapter is disconnected! 

回答

4

您可以使用這種快速indentify你的進程的線程:

using System.Diagnostics; 

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads; 

然後,你可以use kernel32.dll with P/Invoke做任何你需要這些線程。使用OpenThread獲取所需線程的句柄,然後使用該句柄將其掛起並使用SuspendThread

這裏有兩種方法的的P/Invoke聲明:

[DllImport("kernel32.dll")] 
static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId); 

[DllImport("kernel32.dll")] 
static extern uint SuspendThread(IntPtr hThread); 
+0

看起來很有希望,由於引發異常,我給它一個去 – AlexC 2010-11-10 12:58:05

+0

隨時回到這裏,並告訴我們,如果它的工作。 :) – bitbonk 2010-11-10 13:04:12

+2

您還需要GetCurrentThreadId(),這樣您纔不會暫停自己。隨機死鎖很可能,不要分配任何東西。 – 2010-11-10 13:19:25

0

你可以把Thread.Suspend然後Thread.Resume方法,但這些已被取消,不recommneded使用它們。

但是,您可以執行以下操作: 有一個布爾標誌,當設置您將線程置於一個大睡眠狀態時。 或 更好使用ManualResetEvent

+0

謝謝,儘管如此,我需要獲取所有線程對象的位置來完成此操作,而我無法找到它的枚舉器。 (Process.Threads返回一個ProcessThreads集合,而不是線程) – AlexC 2010-11-10 12:50:58

1

您可以通過調用Thread.Suspend掛起線程。文檔給出了大量的「不要這樣做!」棄用警告,但我認爲你是一個有效的用例。

喬恩Skeet認爲you can't enumerate managed threads在正常的C#代碼,雖然他暗示可能的解決方案。

+0

同意:這是一個有效的Suspend用例。 – 2010-11-10 12:47:43

+0

謝謝,儘管如此,我還是需要對所有的Thread對象進行檢查,但是我找不到它的枚舉器。 (Process.Threads返回一個ProcessThreads集合,而不是線程) – AlexC 2010-11-10 12:52:08

1

我假設你不會暫停全部應用程序中的線程,否則將不會有任何運行來解除它們。或者我錯過了什麼?

建議:嘗試給你創建的所有線程提供名稱。任何沒有名稱的線程或者與您的命名約定不匹配的線程都必須由第三方組件創建。這可能會讓您的根本原因更快,而不必暫停大量線程。

+0

嗯,我需要暫停除Thread.CurrentThread之外的所有線程,然後在[插入時間到此處]休眠,然後恢復所有線程。 – AlexC 2010-11-10 12:55:14

1

從我的pov這聽起來不對。

  • 你正在寫哪種測試?如果您正在談論單元測試,那麼這不是單元測試案例 - 聽起來更像是集成測試
  • 請考慮隔離類中的API調用,然後使用依賴注入,以便您可以在沒有第三方庫的情況下進行測試嘲笑/存根,也能招來/測試來自第三方庫
+0

恩說。但現在可能太晚了。 – bitbonk 2010-11-10 13:16:19

+0

這不是一個單元測試或一個集成測試。我只是想要一個小應用程序來驗證問題是由進入調試器引起的(並且它不是由我正在開發的軟件引起的)。第三方庫被包裝在一個自定義的API中(正如你所建議的那樣,我在我的應用程序單元測試中使用了DI),但沒有任何異常從第三方庫中產生,並且該錯誤無法通過製作再現一些特定順序的API調用,很難看到依賴注入如何幫助這裏? – AlexC 2010-11-10 13:19:08