2012-04-12 32 views
38

El nuevo C++ tiene este std :: tipo de hilo. Funciona de maravilla. Ahora me gustaría darle a cada hilo un nombre para una depuración más fácil (como java lo permite). Con pthreads que haría:std :: thread - nombrando su hilo

pthread_setname_np(pthread_self(), "thread_name"); 

pero ¿cómo puedo hacer esto con C++ 0x? Sé que utiliza pthreads debajo en los sistemas Linux, pero me gustaría que mi aplicación sea portátil. ¿Es posible?

+1

En Windows, el nombre del subproceso es una propiedad del depurador (es decir, rastreado fuera de la aplicación). Como resultado, no tiene el equivalente de 'pthread_getname_np' – MSalters

Respuesta

26

Una forma portátil de hacerlo es mantener un mapa de nombres, con la clave del ID del hilo, obtenido de thread::get_id(). Alternativamente, como se sugiere en los comentarios, puede usar una variable thread_local, si solo necesita acceder al nombre desde el hilo.

Si no necesita portabilidad, puede obtener el pthread_t subyacente de thread::native_handle() y hacer los chanchullos específicos de la plataforma que desee con eso. Tenga en cuenta que _np en las funciones de nomenclatura de subprocesos significa "no posicionado", por lo que no se garantiza que estén disponibles en todas las implementaciones de pthreads.

+2

" un mapa de nombres, codificado por el ID del hilo "- ¿o el almacenamiento local del hilo? Asumiendo que la depuración que estás haciendo es solo desde el hilo cuyo nombre quieres saber, por supuesto. –

+1

En términos de un diseño para envolver esta idea, es posible que desee considerar el uso de ThreadFactory en su aplicación, cuyo objetivo es registrar los hilos al momento de la creación y/o abstraer todos los '# ifdef's requeridos si desea use el precompilador para seleccionar el código específico de la plataforma. – Dennis

+7

El objetivo de nombrar hilos es facilitar la depuración, porque el depurador mostraría el nombre del hilo, por lo que mantener algunos mapas de nombres internamente es algo sin sentido ... –

9

Puede utilizar std::thread::native_handle para conseguir la implementación subyacente de rosca definido. No hay una función estándar para eso de forma nativa.

Puede encontrar un ejemplo here.

3

Para Windows [depurador], puede usar fácilmente el método "normal"; http://msdn.microsoft.com/en-gb/library/xcb2z8hs.aspx

sólo necesitan el ID del tema que se puede obtener a través de

#include <windows.h> 
DWORD ThreadId = ::GetThreadId(static_cast<HANDLE>(mThread.native_handle())); 
+0

Eso probablemente funcione, pero no es una solución genérica de C++ y, por lo tanto, multiplataforma. Gracias por sugerirlo de todos modos. –

+2

Oh, definitivamente es solo Windows, pero nadie te había dicho cómo instalarlo en Windows. (Y funciona, lo uso :) –

15

Un intento de hacer un envoltorio para hacer frente a muchos Linuxes, así como Windows. Por favor edita según sea necesario.

#ifdef _WIN32 
#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(uint32_t dwThreadID, const char* threadName) 
{ 

    // DWORD dwThreadID = ::GetThreadId(static_cast<HANDLE>(t.native_handle())); 

    THREADNAME_INFO info; 
    info.dwType = 0x1000; 
    info.szName = threadName; 
    info.dwThreadID = dwThreadID; 
    info.dwFlags = 0; 

    __try 
    { 
     RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); 
    } 
    __except(EXCEPTION_EXECUTE_HANDLER) 
    { 
    } 
} 
void SetThreadName(const char* threadName) 
{ 
    SetThreadName(GetCurrentThreadId(),threadName); 
} 

void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    DWORD threadId = ::GetThreadId(static_cast<HANDLE>(thread->native_handle())); 
    SetThreadName(threadId,threadName); 
} 

#else 
void SetThreadName(std::thread* thread, const char* threadName) 
{ 
    auto handle = thread->native_handle(); 
    pthread_setname_np(handle,threadName); 
} 


#include <sys/prctl.h> 
void SetThreadName(const char* threadName) 
{ 
    prctl(PR_SET_NAME,threadName,0,0,0); 
} 

#endif 
+1

solo para aclarar la parte de Windows de esto es de https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx – BillyT2

+0

En Windows, es posible que también desee utilizar la API SetThreadDescription(): http://stackoverflow.com/a/41446477/434413. Esta es la nueva API oficial, que se está utilizando en herramientas más recientes de MS (el método que se muestra en esta respuesta es la antigua, que solo funciona para procesos que se ejecutan dentro del depurador de Visual Studio en el momento en que se lanza la excepción) –

+0

Nota: El código de Windows con RaiseException está atrapado en tiempo real con el depurador. Es decir. si RaiseException una vez en el inicio de subproceso y adjuntar depurador más tarde, no sabrá nombre de subproceso. – Sergey

2

que he visto tanto este hecho en un sistema anterior a C++ 11 (en el que, básicamente, inventamos nuestra propia clase Thread que era muy similar a std :: hilo) y en el que escribí hace relativamente poco tiempo.

Básicamente, la agrupación realmente pone std :: thread 2 capas hacia abajo, tiene una clase PoolThread que contiene un std :: thread más metadatos como su nombre, ID, etc. y la estructura de control que lo vincula a su grupo de control, y el ThreadPool en sí. Desea usar grupos de subprocesos en el código más subprocesado por varias razones:
1) Puede ocultar todo el explícito "separar", "unir", iniciar subproceso en std :: construcción de subprocesos, etc. de los usuarios. Eso produce MUCHO más seguro & código limpiador.
2) Mejor administración de recursos: Demasiados hilos perjudicarán el rendimiento incluso más que tener muy pocos. Una agrupación bien construida puede hacer cosas avanzadas como el equilibrio de carga automático y la limpieza de hilos colgados o en punto muerto.
3) Reutilización de subprocesos: std :: thread es más fácil de usar ejecutando cada tarea paralela en su propio subproceso. Pero la creación de subprocesos & destrucción es costosa, y puede sofocar fácilmente el aumento de velocidad del procesamiento paralelo si no tiene cuidado. Por lo tanto, normalmente tiene más sentido tener subprocesos de grupo que extraigan tareas de una cola y solo salgan después de recibir alguna señal.
4) Manejo de errores: std :: thread es solo un contexto de ejecución. Si la tarea que está ejecutando arroja una excepción no controlada o std :: thread ITSELF falla, el proceso simplemente se bloqueará allí mismo.Para hacer un multihilo tolerante a fallas, necesita un Pool o algo similar que pueda detectar rápidamente tales cosas y al menos emitir mensajes de error significativos antes de que el proceso falle.

+4

En relación con su punto 2: si agrega lógica a su programa para limpiar subprocesos bloqueados o bloqueados, simplemente está tratando de ocultar errores. Yo recomendaría arreglar el error en su lugar. Algo similar vale para el punto 4: si obtienes una excepción no controlada al nivel superior del hilo, tienes un error fatal en tu código. Nuevamente, la prioridad debe ser corregir el error y no manejar la situación con "gracia". – cmaster

Cuestiones relacionadas