2010-11-10 13 views
7

Tengo un error en mi aplicación que parece mostrarlo solo cuando pause la aplicación en el depurador durante unos minutos. Sospecho que esto se debe a una biblioteca de red de un tercero que estoy usando con un hilo de latido, que se desconecta cuando no puede hacer ping al servidor mientras se detiene el hilo del latido.Pausa de todos los hilos en el proceso actual en tiempo de ejecución

Estoy tratando de escribir una aplicación de caso de prueba para verificar que esta es la causa del error. Para hacerlo, necesito una forma de pausar todos los hilos en la aplicación (que luego reduciré a pausar solo el hilo que sospecho que puede ser el hilo del latido) para simular la pausa de la aplicación en el depurador.

¿Alguien sabe cómo hacer esto? ¿Es posible que un hilo haga que otro duerma?

Gracias, Alex

ACTUALIZACIÓN:

terminé decidiendo que realmente no necesita una aplicación para hacer esto por mí, ya que el objetivo era sólo para comprobar que haciendo una pausa en el depurador estaba causando la desconexión. Por lo tanto, esto es lo que hice ... (Las formas más simples son a menudo la mejor ... o al menos la más simple ...)

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

Y la salida:

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! 

Respuesta

4

Usted puede utilizar esto a indentify rápidamente los hilos de su proceso:

using System.Diagnostics; 

ProcessThreadCollection threads = Process.GetCurrentProcess().Threads; 

a continuación, puede use kernel32.dll with P/Invoke para hacer lo que necesita con esos hilos. Use OpenThread para obtener un control del subproceso deseado y luego colóquelo con SuspendThread usando ese asa.

Éstos son la declaración de P/Invoke para los dos métodos:

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

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

Parece prometedor, gracias, lo intentaré – AlexC

+0

No dude en volver aquí y decirnos si funcionó. :) – bitbonk

+2

También necesita GetCurrentThreadId() para que no se suspenda. El punto muerto aleatorio es bastante probable, no asignen nada. –

0

Se podría llamar a los métodos Thread.Suspend continuación Thread.Resume pero aquellos están en desuso y no está recommneded para usarlos.

Pero usted puede hacer lo siguiente: Tiene un indicador booleano que cuando se establece pone su hilo en un sueño grande. O Es mejor usar ManualResetEvent.

+0

Gracias, aunque para esto, necesitaría obtener todos los objetos Thread para hacer esto, para lo cual no puedo encontrar un enumerador. (Process.Threads devuelve una colección de ProcessThreads, no Threads) – AlexC

1

Puede suspender los hilos llamando al Thread.Suspend. La documentación da un gran "NO HAGAS ESTO!" advertencias de desaprobación, pero creo que el suyo es un caso de uso válido.

Jon Skeet piensa you can't enumerate managed threads en el código normal de C#, aunque insinúa una posible solución.

+0

De acuerdo: este es un caso de uso válido para Suspender. –

+0

Gracias, aunque para esto, necesitaría obtener todos los objetos Thread para hacer esto, para lo cual no puedo encontrar un enumerador. (Process.Threads devuelve una colección de ProcessThreads, no Threads) – AlexC

1

Supongo que no va a pausar todos los hilos en la aplicación, de lo contrario no habrá nada ejecutándose para anular la suspensión. ¿O me he perdido algo?

Sugerencia: Intente dar nombres a todos los hilos que cree. Cualquier subproceso sin nombre, o que no coincida con su convención de nomenclatura, debe haber sido creado por un componente de un tercero. Esto podría llevarlo a la causa raíz más rápido sin tener que pausar muchos subprocesos.

+0

Bueno, necesito pausar todos los hilos excepto Thread.CurrentThread, luego duermo eso para [insert time here], luego reanudo todos los hilos. – AlexC

1

Desde mi punto de vista esto no suena bien.

  • ¿Qué tipo de pruebas estás escribiendo? Si está hablando de pruebas unitarias, entonces este no es un caso de prueba Unitario - suena más como prueba de integración
  • Considere aislar las llamadas API en una clase y luego use la inyección de dependencia para que pueda probar sin la biblioteca de terceros con mocks/stubs y también puede provocar/probar una excepción planteada en la biblioteca de terceros.
+0

Bien dicho. Pero es probable que sea demasiado tarde ahora. – bitbonk

+0

Esto no fue una prueba de unidad o una prueba de integración. Solo quería una pequeña aplicación para verificar que el problema fue causado al ingresar al depurador (y que no fue causado por el software que estoy desarrollando). La biblioteca de terceros está envuelta en una API personalizada como sugirió (y yo uso DI en mis pruebas de la unidad de aplicaciones por la razón que sugiere) pero no se generó ninguna excepción desde la biblioteca de terceros, y el error no se reprodujo al hacer algunas llamadas API en un orden particular, ¿es tan difícil ver cómo la inyección de dependencia ayudaría aquí? – AlexC

Cuestiones relacionadas