Share via


Recomendaciones para depurar subprocesos

En este artículo se proporciona información útil para depurar subprocesos, incluida información sobre cómo establecer nombres de subprocesos para código nativo y administrado.

Sugerencias de C/C++

A continuación se muestran algunas sugerencias que puede usar al depurar subprocesos en código nativo:

  • Puede ver el contenido del Bloque de información de subprocesos escribiendo @TIB en la ventana Inspección o en el cuadro de diálogo Inspección rápida.

  • Puede ver el último código de error del subproceso actual escribiendo @Err en la ventana Inspección o en el cuadro de diálogo Inspección rápida.

  • Las funciones de las bibliotecas en tiempo de ejecución de C (CRT) pueden ser útiles para depurar una aplicación multiproceso. Para obtener más información, consulte _malloc_dbg.

Establecer un nombre de subproceso en C/C++

La denominación de los subprocesos es posible en cualquier edición de Visual Studio. La denominación de los subprocesos es útil para identificar subprocesos de interés en la ventana Subprocesos al depurar un proceso en ejecución. El uso de subprocesos con nombre reconocible también puede ser útil cuando se realiza la depuración final a través de la inspección de volcado de memoria y se analizan las capturas de rendimiento mediante diversas herramientas.

Formas de establecer un nombre de subproceso

Hay dos maneras de establecer el nombre de un subproceso. La primera es a través de la función SetThreadDescription. La segunda es iniciando una excepción determinada mientras el depurador de Visual Studio está asociado al proceso. Cada enfoque tiene ventajas y advertencias. La utilización de SetThreadDescription se admite a partir de Windows 10, versión 1607, o Windows Server 2016.

Cabe mencionar que ambos enfoques se pueden usar juntos, si se quiere, porque los mecanismos con los que funcionan son independientes entre sí.

Establecimiento de un nombre de subproceso mediante SetThreadDescription

Ventajas:

  • Los nombres de los subprocesos son visibles al realizar la depuración en Visual Studio, independientemente de si el depurador estaba asociado o no al proceso en el momento de invocar SetThreadDescription.
  • Los nombres de subprocesos son visibles al realizar la depuración final si se carga un volcado de memoria en Visual Studio.
  • Los nombres de subprocesos también son visibles al usar otras herramientas, como el depurador WinDbg y el analizador de rendimiento de Windows Performance Analyzer.

Advertencias:

  • Los nombres de subprocesos solo son visibles en la versión 15.6 de Visual Studio 2017 y versiones posteriores.
  • Cuando se realiza la depuración final de un archivo de volcado de memoria, los nombres de subprocesos solo son visibles si el bloqueo se creó en la versión 1607 de Windows 10, Windows Server 2016 o versiones posteriores de Windows.

Ejemplo:

#include <windows.h>
#include <processthreadsapi.h>

int main()
{
    HRESULT r;
    r = SetThreadDescription(
        GetCurrentThread(),
        L"ThisIsMyThreadName!"
    );

    return 0;
}

Establecimiento de un nombre de subproceso mediante el inicio de una excepción

Otra manera de establecer un nombre de subproceso en el programa es comunicar el nombre de subproceso deseado al depurador de Visual Studio iniciando una excepción configurada de manera especial.

Ventajas:

  • Funciona en todas las versiones de Visual Studio.

Advertencias:

  • Solo funciona si el depurador está asociado en el momento en que se usa el método basado en excepciones.
  • Los nombres de subprocesos establecidos mediante este método no estarán disponibles en herramientas de análisis de rendimiento ni volcados de memoria.

Ejemplo:

La función SetThreadName que se muestra a continuación muestra este enfoque basado en excepciones. Tenga en cuenta que el nombre del subproceso se copiará automáticamente en el subproceso, de modo que se pueda liberar la memoria del parámetro threadName una vez completada la llamada SetThreadName.

//
// Usage: SetThreadName ((DWORD)-1, "MainThread");
//
#include <windows.h>
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
    DWORD dwType; // Must be 0x1000.
    LPCSTR szName; // Pointer to name (in user addr space).
    DWORD dwThreadID; // Thread ID (-1=caller thread).
    DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
void SetThreadName(DWORD dwThreadID, const char* threadName) {
    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = threadName;
    info.dwThreadID = dwThreadID;
    info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
    __try{
        RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
    }
    __except (EXCEPTION_EXECUTE_HANDLER){
    }
#pragma warning(pop)
}

Establecer un nombre de subproceso en código administrado

La denominación de los subprocesos es posible en cualquier edición de Visual Studio. La denominación de los subprocesos es útil para hacer el seguimiento en la ventana Subprocesos.

Para establecer un nombre de subproceso en código administrado, utilice la propiedad Name.

Ejemplo

public class Needle
{
    // This method will be called when the thread is started.
    public void Baz()
    {
        Console.WriteLine("Needle Baz is running on another thread");
    }
}

public void Main()
{
    Console.WriteLine("Thread Simple Sample");
    Needle oNeedle = new Needle();
    // Create a Thread object.
    System.Threading.Thread oThread = new System.Threading.Thread(oNeedle.Baz);
    // Set the Thread name to "MyThread".
    oThread.Name = "MyThread";
    // Starting the thread invokes the ThreadStart delegate
    oThread.Start();
}