78 votes

Std::thread - nommer votre thread

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

pthread_setname_np(pthread_self(), "nom_du_fil");

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

1 votes

Sur Windows, le nom du thread est une propriété du débogueur (c'est-à-dire suivie en dehors de l'application elle-même). En conséquence, vous n'avez pas l'équivalent de pthread_getname_np

4 votes

Depuis Windows 10, 1607, il y a SetThreadDescription.

41voto

Mike Seymour Points 130519

Une façon portable de faire cela est de maintenir une carte des noms, indexée par l'ID du thread, obtenu à partir de thread::get_id(). Alternativement, comme suggéré dans les commentaires, vous pourriez utiliser une variable thread_local, si vous avez seulement besoin d'accéder au nom à partir du thread.

Si vous n'avez pas besoin de portabilité, alors vous pourriez obtenir le pthread_t sous-jacent à partir de thread::native_handle() et faire tout ce que vous voulez avec cela de manière spécifique à la plate-forme. Sachez que le _np sur les fonctions de nommage de thread signifie "non posix", donc ils ne sont pas garantis d'être disponibles sur toutes les implémentations pthreads.

3 votes

"une carte de noms, indexée par l'ID du thread" - ou stockage local au thread? En supposant que le débogage que vous faites se fait uniquement depuis l'intérieur du thread dont vous voulez connaître le nom, bien sûr.

2 votes

En termes de conception pour envelopper cette idée, vous pourriez envisager d'utiliser une ThreadFactory dans votre application, dont le but est d'enregistrer des threads lors de leur création et/ou de masquer tous les #ifdef nécessaires si vous vouliez utiliser le préprocesseur pour sélectionner du code spécifique à une plateforme.

59 votes

L'ensemble du point de nommer les threads est de faciliter le débogage, car le débogueur afficherait le nom du thread, donc maintenir une sorte de carte de noms en interne est un peu inutile...

37voto

Mark Lakata Points 3458

Une tentative de créer un wrapper pour gérer de nombreux systèmes Linux ainsi que Windows. Veuillez modifier au besoin.

#ifdef _WIN32
#include 
const DWORD MS_VC_EXCEPTION=0x406D1388;

#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
   DWORD dwType; // Doit être 0x1000.
   LPCSTR szName; // Pointeur vers le nom (dans l'espace d'adresse utilisateur).
   DWORD dwThreadID; // ID du thread (-1=thread appelant).
   DWORD dwFlags; // Réservé pour une utilisation future, doit être zéro.
} THREADNAME_INFO;
#pragma pack(pop)

void SetThreadName(uint32_t dwThreadID, const char* threadName)
{

  // DWORD dwThreadID = ::GetThreadId( static_cast( 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( thread->native_handle() ) );
    SetThreadName(threadId,threadName);
}

#elif defined(__linux__)
#include 
void SetThreadName( const char* threadName)
{
  prctl(PR_SET_NAME,threadName,0,0,0);
}

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

2 votes

Juste pour clarifier la partie Windows de ceci provient de msdn.microsoft.com/en-us/library/xcb2z8hs.aspx

4 votes

Sur Windows, vous pouvez également utiliser l'API SetThreadDescription() : stackoverflow.com/a/41446477/434413. C'est la nouvelle API officielle, qui est utilisée dans les nouveaux outils MS (la méthode montrée dans cette réponse est l'ancienne façon de le faire, qui ne fonctionne que pour les processus s'exécutant à l'intérieur du débogueur Visual Studio au moment où l'exception est levée).

0 votes

Note : Le code Windows avec RaiseException est intercepté en temps réel avec le débogueur. C'est-à-dire que si vous RaiseException une fois au démarrage du thread et que vous attachez le débogueur plus tard, il ne connaîtra pas le nom du thread.

14voto

bamboon Points 7089

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

Vous pouvez trouver un exemple ici.

6voto

Soylent Graham Points 170

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

Il suffit d'avoir l'identifiant du thread que vous pouvez obtenir via

#include 
DWORD ThreadId = ::GetThreadId( static_cast( mThread.native_handle() ) );

0 votes

Cela fonctionnera probablement mais ce n'est pas une solution C++ générique et donc multiplateforme. Merci de l'avoir suggéré quand même.

4 votes

Oh, c'est définitivement uniquement pour Windows, mais personne ne vous a réellement dit comment le configurer sous Windows. (Et ça fonctionne, je l'utilise :)

3voto

Zack Yezek Points 134

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

Fondamentalement, le pool place vraiment std::thread à 2 niveaux de profondeur - vous avez une classe PoolThread qui contient un std::thread ainsi que des métadonnées comme son nom, ID, etc. et la structure de contrôle qui le relie à son pool de contrôle, ainsi que le ThreadPool lui-même. Vous souhaitez utiliser des pools de threads dans la plupart du code threadé pour plusieurs raisons :
1) Vous pouvez cacher tous les "detach" explicites, "join", démarrer le thread à la construction de std::thread, etc. aux utilisateurs. Cela produit un code BEAUCOUP plus sûr et plus propre.
2) Meilleure gestion des ressources : Trop de threads peuvent paralyser les performances encore plus que d'en avoir trop peu. Un pool bien construit peut faire des choses avancées comme l'équilibrage automatique de la charge et le nettoyage des threads bloqués ou en panne.
3) Réutilisation des threads : std::thread par lui-même est le plus simple à utiliser en exécutant chaque tâche parallèle sur son propre thread. Mais la création et la destruction de threads sont coûteuses, et peuvent facilement submerger l'accélération de la vitesse du traitement parallèle si vous n'êtes pas prudent. Il est donc généralement plus logique d'avoir des threads de pool qui récupèrent des tâches de travail dans une file d'attente et ne sortent que après avoir reçu un signal.
4) Gestion des erreurs : std::thread est simplement un contexte d'exécution. Si la tâche que vous exécutez jette une exception non gérée ou si std::thread LUI-MÊME échoue, le processus plantera juste là. Pour faire du multithreading tolérant aux pannes, vous avez besoin d'un Pool ou quelque chose de similaire qui peut rapidement attraper de telles choses et au moins émettre des messages d'erreur significatifs avant que le processus ne meure.

7 votes

En ce qui concerne votre point 2 : Si vous ajoutez de la logique à votre programme pour nettoyer les fils suspendus ou bloqués, vous essayez simplement de masquer les bugs. Je recommanderais plutôt de corriger le bug. Quelque chose de similaire s'applique au point 4 : Si vous obtenez une exception non gérée au niveau supérieur du fil, vous avez un bug fatal dans votre code. Encore une fois, la priorité devrait être de corriger le bug et non de gérer la situation "avec élégance".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X