web-dev-qa-db-fra.com

Comment obtenir un identifiant de thread entier en c ++ 11

c ++ 11 a la possibilité d'obtenir l'id du thread actuel, mais il n'est pas convertible en type entier:

cout<<std::this_thread::get_id()<<endl;

sortie: 139918771783456

cout<<(uint64_t)std::this_thread::get_id()<<endl;

erreur: conversion invalide du type 'std :: thread :: id' au type 'uint64_t' identique pour les autres types: conversion invalide du type 'std :: thread :: id' au type 'uint32_t'

Je ne veux vraiment pas faire de casting de pointeur pour obtenir l'identifiant de thread entier. Existe-t-il un moyen raisonnable (standard parce que je veux que ce soit portable) pour le faire?

73
NoSenseEtAl

La solution portable consiste à transmettre vos propres identifiants générés au thread.

int id = 0;
for(auto& work_item : all_work) {
    std::async(std::launch::async, [id,&work_item]{ work_item(id); });
    ++id;
}

Le std::thread::id type ne doit être utilisé que pour des comparaisons, pas pour l’arithmétique (c’est-à-dire comme il est dit sur la boîte: un identifiant). Même sa représentation textuelle produite par operator<< est non spécifié, vous ne pouvez donc pas vous fier à la représentation d'un nombre.

Vous pouvez aussi utiliser une carte de std::thread::id valeurs à votre propre identifiant, et partager cette carte (avec une synchronisation correcte) entre les threads, au lieu de transmettre l'identifiant directement.

28

Vous avez juste besoin de faire

std::hash<std::thread::id>{}(std::this_thread::get_id())

pour obtenir un size_t.

De cppreference :

La spécialisation de template de std::hash pour le std::thread::id class permet aux utilisateurs d’obtenir des hachages des identifiants de threads.

72
888

Une autre id (idée? ^^) serait d’utiliser stringstreams:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

Et utilisez try catch si vous ne voulez pas d'exception si les choses tournent mal ...

22
Mike

Une idée serait d'utiliser le stockage local de threads pour stocker une variable - peu importe le type, dans la mesure où elle respecte les règles de stockage local de thread - d'utiliser l'adresse de cette variable comme "identifiant de thread". Évidemment, tout calcul ne sera pas significatif, mais ce sera un type intégral.

Pour la postérité: pthread_self() renvoie un pid_t Et est posix. Ceci est portable pour une certaine définition de portable.

gettid(), presque certainement pas portable, mais renvoie une valeur conviviale GDB.

6
tgoodhart

Je ne sais vraiment pas à quelle vitesse ça va, mais c'est la solution que j'ai réussi à faire avec guestimate:

const size_t N_MUTEXES=128;//UINT_MAX,not 128  for answer to my original question
hash<std::thread::id> h;
cout<<h(std::this_thread::get_id())%N_MUTEXES<<endl;

Encore une fois, je commence à penser qu'obtenir un pointeur sur la structure et le convertir en unsigned int ou uint64_t est la réponse ... EDIT:

uint64_t get_thread_id()
{
    static_assert(sizeof(std::thread::id)==sizeof(uint64_t),"this function only works if size of thead::id is equal to the size of uint_64");
    auto id=std::this_thread::get_id();
    uint64_t* ptr=(uint64_t*) &id;
    return (*ptr);
}
int main()
{
    cout<<std::this_thread::get_id()<<"  "<<get_thread_id()<<endl;
}

static_assert pour éviter les problèmes infernaux :) La réécriture est facile comparée à la traque de ce type de bogue. :)

4
NoSenseEtAl

thread::native_handle() retourne thread::native_handle_type, qui est un typedef à long unsigned int.

Si thread est construit par défaut, native_handle () renvoie 0. Si un thread de système d'exploitation y est associé, la valeur renvoyée est différente de zéro (il s'agit de pthread_t sur POSIX).

3
Alexey Polonsky

cela dépend de ce que vous voulez utiliser le thread_id pour; vous pouvez utiliser:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

Cela générera un identifiant unique avec votre processus; mais il y a une limite: si vous lancez plusieurs instances du même processus et que chacune d'elles écrit leurs identifiants de thread dans un fichier commun, l'unicité du thread_id n'est pas garantie; en fait, il y a de fortes chances que vous ayez des chevauchements. Dans ce cas, vous pouvez faire quelque chose comme:

#include <sys/time.h>
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;

maintenant, vous avez la garantie d'un identifiant de thread unique dans tout le système.

2
Pandrei

De cette façon, devrait fonctionner:

std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());

N'oubliez pas d'inclure la bibliothèque sstream

2
Federico Rizzo

Peut-être que cette solution pourrait être utile à quelqu'un. Appelez-le une première fois im main(). Attention: names croît indéfiniment.

std::string currentThreadName(){
    static std::unordered_map<std::thread::id,std::string> names;
    static std::mutex mtx;

    std::unique_lock<std::mutex> lock(mtx);

    auto id = std::this_thread::get_id();

    if(names.empty()){
        names[id] = "Thread-main";
    } else if(names.find(id) == names.end()){
        std::stringstream stream;
        stream << "Thread-" << names.size();
        names[id] = stream.str();
    }

    return names[id];
}
1
geh

Une des principales raisons de ne pas utiliser thread :: get_id () est qu'il n'est pas unique dans un seul programme/processus. Cela est dû au fait que l'identifiant peut être réutilisé pour un deuxième thread, une fois le premier thread terminé.

Cela semble être une caractéristique horrible, mais c’est sa version c ++ 11.

0
midjji