web-dev-qa-db-fra.com

std :: thread - nommer votre thread

Le nouveau C++ a ce type std :: thread. Fonctionne comme un charme. Maintenant, je voudrais donner un nom à chaque thread pour un débogage plus facile (comme Java vous le permet). Avec pthreads, je ferais:

pthread_setname_np(pthread_self(), "thread_name");

mais comment puis-je faire cela avec c ++ 0x? Je sais qu'il utilise pthreads en dessous sur les systèmes Linux, mais je voudrais rendre mon application portable. Est-ce possible du tout?

51

Une façon portable de le faire est de maintenir une carte de noms, saisie par l'ID du thread, obtenue à partir de thread::get_id(). Alternativement, comme suggéré dans les commentaires, vous pouvez utiliser une variable thread_local, Si vous avez seulement besoin d'accéder au nom depuis le fil.

Si vous n'avez pas besoin de portabilité, vous pouvez obtenir le pthread_t Sous-jacent de thread::native_handle() et faire les manigances spécifiques à la plate-forme que vous aimez avec cela. Sachez que _np Sur les fonctions de dénomination des threads signifie "pas posix", donc elles ne sont pas garanties d'être disponibles sur toutes les implémentations de pthreads.

31
Mike Seymour

Une tentative de faire un wrapper pour gérer de nombreux Linux ainsi que Windows. Veuillez modifier au besoin.

#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
22
Mark Lakata

Vous pouvez utiliser std::thread::native_handle Pour obtenir le thread défini par l'implémentation sous-jacente. Il n'y a pas de fonction standard pour cela nativement.

Vous pouvez trouver un exemple ici .

9
inf

Pour Windows [débogueur], vous pouvez facilement utiliser la méthode "normale"; http://msdn.Microsoft.com/en-gb/library/xcb2z8hs.aspx

Vous avez juste besoin de l'ID de thread que vous pouvez obtenir via

#include <windows.h>
DWORD ThreadId = ::GetThreadId( static_cast<HANDLE>( mThread.native_handle() ) );
4
Soylent Graham

J'ai vu cela dans un système antérieur à c ++ 11 (où nous avons essentiellement inventé notre propre classe Thread qui était très similaire à std :: thread) et dans une que j'ai écrite assez récemment.

Fondamentalement, le pool place vraiment les couches std :: thread 2 - vous avez une classe PoolThread qui contient un std :: thread plus des métadonnées comme son nom, son ID, etc. et la structure de contrôle qui le relie à son pool de contrôle, et le ThreadPool lui-même. Vous souhaitez utiliser des pools de threads dans la plupart des codes threadés pour plusieurs raisons:
1) Vous pouvez masquer tous les "détacher", "rejoindre" explicites, démarrer le thread sur la construction std :: thread, etc. des utilisateurs. Cela produit BEAUCOUP de code plus sûr et plus propre.
2) Meilleure gestion des ressources: trop de threads paralyseront encore plus les performances que trop peu. Un pool bien construit peut faire des choses avancées comme l'équilibrage de charge automatique et le nettoyage des threads bloqués ou bloqués.
3) Réutilisation des threads: std :: thread en lui-même est plus facile à utiliser en exécutant chaque tâche parallèle sur son propre thread. Mais la création et la destruction de threads coûtent cher et peuvent facilement réduire la vitesse du traitement parallèle si vous n'y faites pas attention. Ainsi, il est généralement plus judicieux d'avoir des threads de pool qui tirent les tâches de travail d'une file d'attente et ne quittent qu'après avoir reçu un signal.
4) Gestion des erreurs: std :: thread n'est qu'un contexte d'exécution. Si la tâche sur laquelle vous l'exécutez lève une exception non gérée ou si std :: thread ITSELF échoue, le processus se bloquera juste là. Pour effectuer un multithreading tolérant aux pannes, vous avez besoin d'un pool ou quelque chose de similaire qui peut rapidement détecter de telles choses et au moins émettre des messages d'erreur significatifs avant la fin du processus.

2
Zack Yezek