2010-11-10 19 views
7

Nella mia app ho un bug che sembra mostrare il suo volto solo quando sospendo l'app nel debugger per alcuni minuti. Sospetto che ciò sia dovuto a una libreria di rete di terze parti che sto usando con un thread heartbeat, che viene disconnesso quando non può eseguire il ping del server mentre il thread heartbeat è in pausa.Sospensione di tutti i thread nel processo corrente in fase di esecuzione

Sto provando a scrivere un'app di test case per verificare che questa sia la causa del bug. Per fare ciò, ho bisogno di un modo per mettere in pausa tutti i thread nell'app (che in seguito mi limiterò a mettere in pausa solo il thread che sospetto possa essere il thread heartbeat) per simulare l'interruzione dell'app nel debugger.

Qualcuno sa come fare? È persino possibile che un thread faccia dormire un altro?

Grazie, Alex

UPDATE:

ho finito per decidere che non ho davvero bisogno di un app per fare questo per me, visto che il punto era solo per verificare che una pausa nel debugger stava causando la disconnessione. Quindi, ecco quello che ho fatto ... (I modi più semplici sono spesso le migliori ... o per lo meno la più semplice ...)

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(); 
    } 

E l'output:

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! 

risposta

4

È possibile utilizzare questo per identificare rapidamente i fili del vostro processo:

using System.Diagnostics; 

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads; 

Poi si può use kernel32.dll with P/Invoke di fare tutto ciò che ti serve con quei fili. Utilizzare OpenThread per ottenere un handle per il thread desiderato e quindi sospenderlo con SuspendThread utilizzando quell'handle.

Ecco la dichiarazione P/Invoke per i due metodi:

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

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

Sembra promettente, grazie, ci provo io – AlexC

+0

Sentiti libero di tornare qui e dirci se ha funzionato. :) – bitbonk

+2

Hai anche bisogno di GetCurrentThreadId() in modo da non sospenderti. La situazione di stallo casuale è abbastanza probabile, non assegnare nulla. –

0

Si può chiamare l'Thread.Suspend poi Thread.Resume metodi, ma questi sono deprecata e non è recommneded usarli.

Ma è possibile fare quanto segue: Avere una bandiera booleana che quando si imposta si mette il filo in un grande sonno. OR Meglio usare ManualResetEvent.

+0

Grazie, anche se per questo, avrei bisogno di ottenere tutti gli oggetti Thread per farlo, che non riesco a trovare un enumeratore per. (Process.Threads restituisce una raccolta di ProcessThreads, non Threads) – AlexC

1

È possibile sospendere i thread chiamando Thread.Suspend. La documentazione dà grande "NON FARE QUESTO!" avvertimenti sulla deprecazione, ma penso che il tuo sia un caso d'uso valido.

Jon Skeet pensa you can't enumerate managed threads nel normale codice C#, sebbene indichi una possibile soluzione.

+0

Accetto: questo è un caso d'uso valido per Suspend. –

+0

Grazie, anche se per questo, avrei bisogno di ottenere tutti gli oggetti Thread per farlo, per cui non riesco a trovare un enumeratore. (Process.Threads restituisce una raccolta di ProcessThreads, non Threads) – AlexC

1

Suppongo che tu non abbia intenzione di mettere in pausa tutti i i thread nell'applicazione, altrimenti non ci sarà nulla in esecuzione per annullarli. O mi sono perso qualcosa?

Un suggerimento: prova a dare nomi a tutti i thread che crei. Qualsiasi thread senza un nome o che non corrisponde alla tua convenzione di denominazione, deve essere stato creato da un componente di terze parti. Questo potrebbe portarti alla causa principale più velocemente senza dover mettere in pausa molti thread.

+0

Bene, ho bisogno di mettere in pausa tutti i thread tranne Thread.CurrentThread, quindi di dormire per [inserire qui il tempo], quindi riprendere tutti i thread. – AlexC

1

Dal mio pov non sembra giusto.

  • Che tipo di test stai scrivendo? Se si sta parlando di unit test, questo non è un caso di test unitario - sembra più un test di integrazione
  • Si consiglia di isolare le chiamate API in una classe e quindi utilizzare l'iniezione dependendcy in modo da poter eseguire il test senza la libreria di terze parti con deride/stub e può anche provocare/testare un'eccezione sollevata dalla libreria di terze parti
+0

Ben detto. Ma probabilmente è troppo tardi adesso. – bitbonk

+0

Questo non era un test unitario o un test di integrazione. Volevo solo una piccola app per verificare che il problema fosse causato dall'inserimento del debugger (e che non fosse causato dal software che sto sviluppando). La libreria di terze parti è racchiusa in un'API personalizzata come suggerito (e utilizzo DI nei miei test di unità per il motivo che suggerisci) ma non è stata sollevata alcuna eccezione dalla libreria di terze parti e il bug non è stato riproducibile effettuando alcune chiamate API in un ordine particolare, così difficile da vedere in che modo l'iniezione della dipendenza sarebbe utile qui? – AlexC