25

Una cosa que me molesta cuando depuro programas en Visual Studio (2005 en mi caso) es que cuando uso "paso sobre" (presionando F10) para ejecutar En la siguiente línea de código, a menudo termino alcanzando esa línea de código en un hilo totalmente diferente al que estaba viendo. Esto significa que todo el contexto de lo que estaba haciendo se perdió."Paso" al depurar programas multiproceso en Visual Studio

¿Cómo puedo solucionar esto?

Si esto es posible en versiones posteriores de Visual Studio, me gustaría saberlo también.

Establecer un punto de interrupción en la siguiente línea de código que tiene una condicional para romper solamente para este hilo no es la respuesta que estoy buscando, ya que es demasiado trabajo sea útil para mí :)

Respuesta

37

Creo que hay una sola respuesta a su pregunta, que ha descartado como 'mucho trabajo'. Sin embargo, creo que es porque lo estás haciendo mal. Permítanme presentar los pasos para agregar un punto de interrupción condicional en Thread ID, que son extremadamente fáciles, pero no obvios hasta que los conozca.

  1. Detener el depurador en un punto donde se encuentre en el hilo correspondiente que desee continuar con la depuración de (que yo supongo que es por lo general el primer hilo que llega allí).

  2. Ingrese $TID en la ventana del reloj.

  3. Añadir un punto de ruptura con la condición $TID == <valor de $ TID desde la ventana de vigilancia>,
    Ejemplo: $TID == 0x000016a0

  4. continuar la ejecución.

$TID es una variable mágica para compiladores de Microsoft (por lo menos desde Visual Studio     2003) que tiene el valor del ID del hilo actual. Lo hace mucho más fácil que mirar (FS + 0x18) [0x24]. = D

Dicho esto, puede obtener el mismo comportamiento que los puntos de corte One-Shot del depurador con algunas macros simples. Cuando te pones de pie, el depurador, detrás de las escenas, establece un punto de interrupción, corre hacia ese punto de interrupción y luego lo elimina. La clave para una interfaz de usuario consistente es eliminar esos puntos de interrupción si se golpea CUALQUIER punto de corte.

Los siguientes dos macros proporcionan Paso a paso por y Run To Cursor para el subproceso actual. Esto se lleva a cabo de la misma manera que el depurador, con los puntos de interrupción eliminados después de la ejecución, independientemente de qué punto de interrupción se golpee.

Deseará asignar una combinación de teclas para ejecutarlas.

NOTA: Una advertencia - El Paso a paso por macro sólo funciona correctamente si el cursor está en la línea que desea pasar por encima. Esto se debe a que determina la ubicación actual por la ubicación del cursor y simplemente agrega una al número de línea. Es posible que pueda reemplazar el cálculo de ubicación con información sobre el punto de ejecución actual, aunque no pude localizar esa información desde el IDE de macro.

¡Aquí están y buena suerte, cacería de errores!

Para utilizar estas macros en Visual Studio:
1. Abra el IDE de Macro (desde el menú, seleccionar: Herramientas-> Macros-> IDE Macro ...)
2. Agregar un nuevo archivo de código (desde el menú: seleccionar: Proyecto-> Agregar nuevo elemento ..., elegir código del archivo y haga clic en Agregar )
3. Pegar en este código.
4. Guarde el archivo.

Para añadir combinaciones de teclas para ejecutar estas macros en Visual Studio:
1. Opciones de apertura (desde el menú, seleccionar: Herramientas-> Opciones)
2. Expandir a Ambiental-> Teclado
3. En Mostrar comandos que contienen:, tipo Macros. para ver todas sus macros.
4. Seleccione una macro, haga clic en en la combinación de teclas Press:
5. Tipo de la combinación que desea utilizar (de corrección borra combos mecanografiadas)
6. Haga clic en Asignar para fijar el acceso directo para ejecutar la macro seleccionada.

Imports System 
Imports EnvDTE 
Imports EnvDTE80 
Imports System.Diagnostics 

Public Module DebugHelperFunctions 

    Sub RunToCursorInMyThread() 
     Dim textSelection As EnvDTE.TextSelection 
     Dim myThread As EnvDTE.Thread 
     Dim bp As EnvDTE.Breakpoint 
     Dim bps As EnvDTE.Breakpoints 

     ' For Breakpoints.Add() 
     Dim FileName As String 
     Dim LineNumber As Integer 
     Dim ThreadID As String 

     ' Get local references for ease of use 
     myThread = DTE.Debugger.CurrentThread 
     textSelection = DTE.ActiveDocument.Selection 

     LineNumber = textSelection.ActivePoint.Line 
     FileName = textSelection.DTE.ActiveDocument.FullName 
     ThreadID = myThread.ID 

     ' Add a "One-Shot" Breakpoint in current file on current line for current thread 
     bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID) 

     ' Run to the next stop 
     DTE.Debugger.Go(True) 

     ' Remove our "One-Shot" Breakpoint 
     For Each bp In bps 
      bp.Delete() 
     Next 
    End Sub 

    Sub StepOverInMyThread() 
     Dim textSelection As EnvDTE.TextSelection 
     Dim myThread As EnvDTE.Thread 
     Dim bp As EnvDTE.Breakpoint 
     Dim bps As EnvDTE.Breakpoints 

     ' For Breakpoints.Add() 
     Dim FileName As String 
     Dim LineNumber As Integer 
     Dim ThreadID As String 

     ' Get local references for ease of use 
     myThread = DTE.Debugger.CurrentThread 
     textSelection = DTE.ActiveDocument.Selection 

     LineNumber = textSelection.ActivePoint.Line 
     FileName = textSelection.DTE.ActiveDocument.FullName 
     ThreadID = myThread.ID 
     LineNumber = LineNumber + 1 

     ' Add a "One-Shot" Breakpoint in current file on current line for current thread 
     bps = DTE.Debugger.Breakpoints.Add("", FileName, LineNumber, 1, "$TID == " & ThreadID) 

     ' Run to the next stop 
     DTE.Debugger.Go(True) 

     ' Remove our "One-Shot" Breakpoint 
     For Each bp In bps 
      bp.Delete() 
     Next 
    End Sub 


End Module 

Negación: Escribí estas macros en Visual Studio 2005 . Probablemente pueda usarlos bien en Visual Studio 2008. Pueden requerir modificaciones para Visual Studio 2003 y versiones anteriores.

+0

¿Funciona esto para cualquiera? No pude hacer que funcione. –

+0

Funciona para mí. = D ¿Cuál fue tu error? – Aaron

+0

@ Aaron: Estoy usando VS 2008 cuando ingreso $ TID en la ventana de Inspección recibo el error "El nombre no existe en el contexto actual" – akif

21

Puede congelar un hilo diferente o cambiar a otro hilo usando la ventana de depuración de Threads (Ctrl + Alt + H).

+0

Gracias. ¡Esto es lo más cercano a una buena solución para esto que he visto hasta ahora! – Laserallan

+4

Eso es lo que estoy haciendo también, la pregunta es ... ¿por qué un solo paso cambia el hilo que se está ejecutando? –

6

La manera simple de depurar un hilo en particular es congelar todos los demás hilos desde la ventana de Subprocesos.

+3

¿No hay forma de hacer que VS no cambie los hilos? ¿En qué situación tiene sentido que un depurador cambie a un hilo diferente cuando está pasando por una línea y espera simplemente llegar al siguiente? – stu

+0

¿Alguien tiene una macro para esto?Sería bueno para un complemento o una macro al golpear paso a paso/sobre congelar todos los otros hilos, rastrear la línea y luego descongelar todos los otros hilos. Eso es efectivamente lo que quiero hacer, debería haber una manera de automatizar eso. – stu

+0

Por supuesto, debería funcionar correctamente en Visual Studio en primer lugar. – stu

2

[Ctrl + D, E] o [Ctrl + Alt + H] - abre la ventana de rosca (utilizado para controlar, congelar y roscas nombre)

La ventana hilo le permite seleccionar si desea mostrar la ubicación de los otros hilos en el estudio visual. Ese es un buen recordatorio para mí de que el hilo actual que estoy depurando no es el único en juego. Al pasar el marcador de hilo, obtendrá el nombre y la identificación de los hilos.

Más consejos encontrar en: http://devpinoy.org/blogs/jakelite/archive/2009/01/10/5-tips-on-debugging-multi-threaded-code-in-visual-studio-net.aspx

2

Al parecer, Visual Studio 2010 sólo se cambia a otros hilos si pulsa F10 cuando el depurador tenía que romper en ese hilo antes o si es un punto de interrupción se establece que será golpeado en este hilo

que utiliza el código siguiente para probar el comportamiento:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var t = new Thread(new ThreadStart(Work)); 
     t.Start(); 

     for (int i = 0; i < 20; i++) 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("............"); 
     } 

     t.Join(); 
    } 

    static void Work() 
    { 
     for (int i = 0; i < 20; i++) 
     { 
      Thread.Sleep(1000); 
      Console.WriteLine("ZZzzzzzzzzzzzzzz"); 
     } 
    } 
} 

Si sólo stept al programa o añadir un punto de interrupción en el método Main(), golpeando F10 pocos pasos a través del código desde el hilo principal .

Si agrega un punto de interrupción en el método Work(), el depurador pasa por ambos hilos.

Este comportamiento de Visual Studio tiene sentido, pero todo parece ser una característica no documentada para mí ...

1

Recientemente tuve el mismo problema de la depuración sólo un cierto hilo. Si bien no descontaré la respuesta anterior como muy completa y valiosa (y desearía haberla encontrado hace 2 días), implementé lo siguiente para ayudar con la resolución de problemas "cotidianos".

Esta idea es solo una solución simple cuando se ejecutan varias instancias de la misma clase en varios subprocesos, lo que nuestra aplicación está haciendo en todo momento.

Inicializamos todas las instancias de clase con un ID o nombre único, por lo que sabemos cómo o por qué se creó la instancia. Entonces, cuando tenemos que depurar una instancia específica (es decir, hilo) - y no congelar otros hilos, añadimos el siguiente:

if (instance.ID == myID) 
{ 
    // Assert BreakPoint 
} 

En nuestro caso, establecemos las identificaciones fijas, por lo que sabemos el ID queremos solucionar problemas cuando tenemos un problema.

Cuestiones relacionadas