c ++ 11 hat die Möglichkeit, die aktuelle Thread-ID abzurufen, kann jedoch nicht in einen ganzzahligen Typ umgewandelt werden:
cout<<std::this_thread::get_id()<<endl;
Ausgabe: 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
Fehler: Ungültige Umwandlung vom Typ 'std :: thread :: id' in Typ 'uint64_t'. Gleiches gilt für andere Typen. Ungültige Umwandlung vom Typ 'std :: thread :: id' in Typ 'uint32_t'.
Ich möchte wirklich kein Zeiger-Casting durchführen, um die Ganzzahl-Thread-ID zu erhalten. Gibt es eine vernünftige Möglichkeit (Standard, weil ich möchte, dass es portabel ist), dies zu tun?
c++
multithreading
c++11
NoSenseEtAl
quelle
quelle
operator<<
anscheinend in Ordnung ist).thread::id
nicht als Ganzzahl dargestellt wird. Die Seite, auf die Sie verlinken, verwendet ein Array, das nach Thread-ID indiziert ist. Haben Sie darüber nachgedacht,map<thread::id, int>
stattdessen ein zu verwenden? Anschließend können Sie die bereits für dieid
Klasse definierten Vergleichsoperatoren verwenden, ohne Konvertierungen vorzunehmen. Der Standard definiert auchhash<thread::id>
, so dass Sie auch die ungeordneten Container verwenden können.Antworten:
Die tragbare Lösung besteht darin, Ihre eigenen generierten IDs an den Thread zu übergeben.
Der
std::thread::id
Typ darf nur für Vergleiche verwendet werden, nicht für Arithmetik (dh wie auf der Dose steht: ein Bezeichner ). Sogar die von dargestellte Textdarstellungoperator<<
ist nicht spezifiziert , sodass Sie sich nicht darauf verlassen können, dass es sich um die Darstellung einer Zahl handelt.Sie können auch eine Zuordnung von
std::thread::id
Werten zu Ihrer eigenen ID verwenden und diese Zuordnung (mit ordnungsgemäßer Synchronisierung) für die Threads freigeben, anstatt die ID direkt zu übergeben.quelle
Sie müssen nur tun
um eine zu bekommen
size_t
.Aus der Referenz :
quelle
std::hash<std::thread::id>()(std::this_thread::get_id())
, nicht wahr?Eine andere ID (Idee? ^^) wäre die Verwendung von Stringstreams:
Und verwenden Sie try catch, wenn Sie keine Ausnahme wünschen, falls etwas schief geht ...
quelle
std::thread::id
Zeichen als Zeichen gedruckt wird, aus denen eine Ganzzahl besteht, ähnlich wie nicht garantiert wird, dass die Thread-ID intern durch eine Ganzzahl dargestellt wird.std::thread::id
keine ganze Zahl?std::thread::id
als Typ anstelle einer Ganzzahl, dafür gibt es sie. Und interpretieren Sie die Zeichenfolgendarstellung nicht als Ziffern, aus denen eine Zahl besteht. Behandeln Sie es als undurchsichtig oder als Debugging- / Protokollierungsausgabe.Eine Idee wäre, den lokalen Thread-Speicher zum Speichern einer Variablen zu verwenden - egal welcher Typ, solange er den Regeln des lokalen Thread-Speichers entspricht - und dann die Adresse dieser Variablen als "Thread-ID" zu verwenden. Offensichtlich wird jede Arithmetik nicht sinnvoll sein, aber es wird ein integraler Typ sein.
Für die Nachwelt: Gibt
pthread_self()
a zurückpid_t
und ist posix. Dies ist portabel für einige Definitionen von portabel.gettid()
, mit ziemlicher Sicherheit nicht tragbar, aber es gibt einen GDB-freundlichen Wert zurück.quelle
pthread_self()
gibt tatsächlich a zurückpthread_t
, was undurchsichtig ist (im Gegensatz zupid_t
(zurückgegeben vongettid()
), das zwar auch plattformspezifisch ist, aber anscheinend zumindest eine ganze Zahl ist). Aber +1 für das erste bisschen, es hat mein Problem gelöst!Ich weiß wirklich nicht, wie schnell das geht, aber das ist die Lösung, die ich zu Gast bekommen habe:
Wieder fange ich an zu denken, dass es die Antwort ist, einen Zeiger auf die Struktur zu bekommen und ihn in unsigned int oder uint64_t umzuwandeln ... EDIT:
static_assert, um höllische Probleme zu vermeiden :) Das Umschreiben ist im Vergleich zur Suche nach solchen Fehlern einfach. :) :)
quelle
hash
Funktion keine doppelten Werte erhalten, geschweige denn , wenn Sie%% .std::this_thread::get_id()
! Aber du brauchst es wahrscheinlich nicht. Ein paar Threads, die miteinander geteilt werden, verursachen nicht das gleiche massive Problem wie jeder Thread, der mit jedem anderen Thread geteilt wird. So etwasconst size_t N_COUNTERS = 128; struct Counter { std::atomic<int> counter; char pad[CACHE_LINE_SIZE - sizeof(atomic<int>); } counters[N_COUNTERS];
ist wahrscheinlich in Ordnung. (Ein Atomic oder Spinlock für eine sehr leichte Synchronisation.)atomic<int>
stattint
ist eine dramatische Verlangsamung, auch ohne Streit.thread::native_handle()
gibt zurückthread::native_handle_type
, was ein typedef istlong unsigned int
.Wenn der Thread standardmäßig erstellt wird, gibt native_handle () 0 zurück. Wenn ein Betriebssystem-Thread angeschlossen ist, ist der Rückgabewert ungleich Null (unter POSIX ist er pthread_t).
quelle
std::thread::native_handle_type
was ein typedef istlong unsigned
? In 30.3.1 / 1 können wir nur sehentypedef implementation-defined native_handle_type; // See 30.2.3
Auf diese Weise sollte funktionieren:
Denken Sie daran, Library Sstream einzuschließen
quelle
std::stringstream
, können Sie es verwendenoperator >>
, um in int zu konvertieren. Ich würde eigentlich lieberuint64_t
als Artid
statt ,int
wenn ich bin sicher , dass dasid
Integral ist.es hängt davon ab, wofür Sie die thread_id verwenden möchten; Sie können verwenden:
Dadurch wird während des Prozesses eine eindeutige ID generiert. Es gibt jedoch eine Einschränkung: Wenn Sie mehrere Instanzen desselben Prozesses starten und jede von ihnen ihre Thread-IDs in eine gemeinsame Datei schreibt, kann die Eindeutigkeit der thread_id nicht garantiert werden. In der Tat ist es sehr wahrscheinlich, dass Sie Überschneidungen haben. In diesem Fall können Sie Folgendes tun:
Jetzt sind Ihnen systemweit eindeutige Thread-IDs garantiert.
quelle
operator<<
kann alles drucken , es ist falsch anzunehmen, dass er immer eine ganze Zahl druckt.Ein Hauptgrund, thread :: get_id () nicht zu verwenden, ist, dass es in einem einzelnen Programm / Prozess nicht eindeutig ist. Dies liegt daran, dass die ID nach Abschluss des ersten Threads für einen zweiten Thread wiederverwendet werden kann.
Dies scheint eine schreckliche Funktion zu sein, aber es ist was in C ++ 11.
quelle
Eine andere Alternative:
Der von g ++ in x86 64-Bit generierte Code für diese Funktion lautet nur:
Dh ein einzelner Zweig ohne Synchronisation, der korrekt vorhergesagt wird, außer wenn Sie die Funktion zum ersten Mal aufrufen. Danach nur noch ein einziger Speicherzugriff ohne Synchronisation.
quelle
thread_local
Beschreibt bereits die Speicherdauer fürtid
. Dasstatic
fürthread_counter
ist, weil Sie es nicht außerhalb dieser Kompilierungseinheit verfügbar machen möchten.0
es sich um eine gültige ID handelt, ist dies ein guter Punkt und kann stattdessen mithilfe von Vorinkrementen behoben werden. Ich werde die Antwort ändern, um das zu tun.Vielleicht ist diese Lösung für jemanden hilfreich. Nenne es ein erstes Mal im
main()
. Warnung:names
wächst auf unbestimmte Zeit.quelle