web-dev-qa-db-de.com

So drucken Sie pthread_t

Gesucht, aber keine befriedigende Antwort gefunden. 

Ich weiß, dass es keinen portablen Weg gibt, einen pthread_t zu drucken. 

Wie machst du das in deiner App?

Update:  

Eigentlich brauche ich nicht pthread_t, sondern eine kleine numerische ID, die in der Debug-Nachricht verschiedene Threads identifiziert. 

Auf meinem System (64 Bit RHEL 5.3) ist es als vorzeichenlose long int definiert, daher ist es eine große Zahl. Wenn Sie nur drucken, ist dies ein wertvoller Platz in der Debug-Zeile. Wie ordnet gdb kurze Tids zu?

47
dimba

Dies gibt eine hexadezimale Darstellung eines pthread_t aus, egal was das ist:

void fprintPt(FILE *f, pthread_t pt) {
  unsigned char *ptc = (unsigned char*)(void*)(&pt);
  fprintf(f, "0x");
  for (size_t i=0; i<sizeof(pt); i++) {
    fprintf(f, "%02x", (unsigned)(ptc[i]));
  }
}

Um nur eine kleine ID für jeden pthread_t zu drucken, könnte etwas davon verwendet werden (diesmal unter Verwendung von Iostreams):

void printPt(std::ostream &strm, pthread_t pt) {
  static int nextindex = 0;
  static std::map<pthread_t, int> ids;
  if (ids.find(pt) == ids.end()) {
    ids[pt] = nextindex++;
  }
  strm << ids[pt];
}

Abhängig von der Plattform und der tatsächlichen Darstellung von pthread_t kann es erforderlich sein, einen operator< für pthread_t zu definieren, da std::map eine Reihenfolge für die Elemente erfordert:

bool operator<(const pthread_t &left, const pthread_t &right) {
  ...
}
31
sth

GDB verwendet die Thread-ID (aka Kernel Pid, ​​kurz LWP) für kurze Nummern unter Linux. Versuchen:

  #include <syscall.h>
  ...

    printf("tid = %d\n", syscall(SYS_gettid));
23

In diesem Fall hängt es vom Betriebssystem ab, da der POSIX-Standard nicht mehr benötigt, dass pthread_t ein arithmetischer Typ ist :

IEEE Std 1003.1-2001/Cor 2-2004, Position XBD/TC2/D6/26 wird angewendet, wobei pthread_t zur Liste der Typen hinzugefügt wird, die nicht arithmetische Typen sein müssen, wodurch pthread_t als Struktur definiert werden kann.

Sie müssen in Ihrem sys/types.h-Header nachsehen, wie pthread_t implementiert wird. dann können Sie es ausdrucken, wie Sie es für richtig halten. Da es keine tragbare Möglichkeit gibt, dies zu tun, und Sie nicht sagen, welches Betriebssystem Sie verwenden, gibt es nicht viel mehr zu sagen.

Edit: zur Beantwortung Ihrer neuen Frage, GDB weist bei jedem Start eines neuen Threads eine eigene Thread-ID zu :

Zu Debugging-Zwecken ordnet gdb jedem Thread in Ihrem Programm eine eigene Thread-Nummer - immer eine einzelne Ganzzahl - zu. 

Wenn Sie in jedem Thread eine eindeutige Nummer drucken möchten, besteht die sauberste Option wahrscheinlich darin, jedem Thread mitzuteilen, welche Nummer beim Start verwendet werden soll.

14
James McNellis

OK, scheint das meine endgültige Antwort zu sein. Wir haben 2 tatsächliche Probleme:

  • So erhalten Sie kürzere eindeutige IDs für den Thread zur Protokollierung.
  • Auf jeden Fall müssen wir eine echte pthread_t-ID für den Thread drucken (um zumindest mit den POSIX-Werten zu verknüpfen).

1. POSIX-ID drucken (pthread_t)

Sie können pthread_t einfach als Array von Bytes behandeln, wobei für jedes Byte hexadezimale Ziffern gedruckt werden. Sie sind also nicht auf einen bestimmten Formattyp beschränkt. Das einzige Problem ist die Bytereihenfolge. Sie mögen wahrscheinlich, wenn die Reihenfolge Ihrer gedruckten Bytes dieselbe ist wie für das einfache "int". Hier ist ein Beispiel für Little-Endian und für Big-Endian sollte nur die Reihenfolge (unter Definieren?) Umgekehrt werden:

#include <pthread.h>
#include <stdio.h>

void print_thread_id(pthread_t id)
{
    size_t i;
    for (i = sizeof(i); i; --i)
        printf("%02x", *(((unsigned char*) &id) + i - 1));
}

int main()
{
    pthread_t id = pthread_self();

    printf("%08x\n", id);
    print_thread_id(id);

    return 0;
}

2. Erhalte kürzere druckbare Thread-ID

In einem der vorgeschlagenen Fälle sollten Sie die reale Thread-ID (Posix) in den Index einiger Tabellen übersetzen. Es gibt jedoch zwei deutlich unterschiedliche Ansätze:

2.1. Fäden nachverfolgen.

Sie können die Thread-ID aller in der Tabelle vorhandenen Threads nachverfolgen (ihre pthread_create () - Aufrufe sollten eingeschlossen werden) und eine überladene ID-Funktion haben, die nur den Tabellenindex und keine echte Thread-ID enthält. Dieses Schema ist auch sehr nützlich für alle internen Thread-bezogenen Debugging- und Ressourcenverfolgungen. Offensichtlicher Vorteil ist der Nebeneffekt der Trace/Debug-Funktion auf Thread-Ebene mit zukünftiger Erweiterung. Nachteil ist die Notwendigkeit, die Erstellung/Zerstörung von Threads zu verfolgen.

Hier ist ein teilweises Pseudocode-Beispiel:

pthread_create_wrapper(...)
{
   id = pthread_create(...)
   add_thread(id);
}

pthread_destruction_wrapper()
{
   /* Main problem is it should be called.
      pthread_cleanup_*() calls are possible solution. */
   remove_thread(pthread_self());
}

unsigned thread_id(pthread_t known_pthread_id)
{
  return seatch_thread_index(known_pthread_id);
}

/* user code */
printf("04x", thread_id(pthread_self()));

2.2. Registrieren Sie einfach eine neue Thread-ID.

Rufen Sie während der Protokollierung pthread_self () auf und suchen Sie nach der internen Tabelle, wenn er den Thread kennt. Wenn ein Thread mit einer solchen ID erstellt wurde, wird dessen Index verwendet (oder er wird von einem vorherigen Thread erneut verwendet IDs für den gleichen Moment). Wenn die Thread-ID noch nicht bekannt ist, wird ein neuer Eintrag erstellt, sodass ein neuer Index erstellt/verwendet wird.

Vorteil ist die Einfachheit. Nachteil ist keine Verfolgung der Erstellung/Zerstörung von Threads. Um dies zu verfolgen, sind einige externe Mechanismen erforderlich.

7

Auf Centos 5.4 x86_64 ist pthread_t ein Typedef für eine vorzeichenlose long.

Deshalb könnten wir das tun ...

#include <iostream>
#include <pthread.h>

int main() {
    pthread_t x;
    printf("%li\n", (unsigned long int) x);
    std::cout << (unsigned long int) x << "\n";
}
4
Bill Lynch

Sie könnten so etwas tun:

int thread_counter = 0;
pthread_mutex_t thread_counter_lock = PTHREAD_MUTEX_INITIALIZER;

int new_thread_id() {
    int rv;
    pthread_mutex_lock(&thread_counter_lock);
    rv = ++thread_counter;
    pthread_mutex_unlock(&thread_counter_lock);
    return rv;
}

static void *threadproc(void *data) {
    int thread_id = new_thread_id();
    printf("Thread %d reporting for duty!\n", thread_id);
    return NULL;
}

Wenn Sie sich auf GCC verlassen können (clang funktioniert auch in diesem Fall), können Sie auch Folgendes tun:

int thread_counter = 0;

static void *threadproc(void *data) {
    int thread_id = __sync_add_and_fetch(&thread_counter, 1);
    printf("Thread %d reporting for duty!\n", thread_id);
    return NULL;
}

Wenn Ihre Plattform dies unterstützt, eine ähnliche Option:

int thread_counter = 0;
int __thread thread_id = 0;

static void *threadproc(void *data) {
    thread_id = __sync_add_and_fetch(&thread_counter, 1);
    printf("Thread %d reporting for duty!\n", thread_id);
    return NULL;
}

Dies hat den Vorteil, dass Sie thread_id nicht in Funktionsaufrufen übergeben müssen, aber es funktioniert nicht, z. unter Mac OS.

3
LnxPrgr3

wenn pthread_t nur eine Zahl ist; das wäre am einfachsten.

int get_tid(pthread_t tid)
{
    assert_fatal(sizeof(int) >= sizeof(pthread_t));

    int * threadid = (int *) (void *) &tid;
    return *threadid;
}
3
sgowd

Eine Nachschlagetabelle (pthread_t : int) kann zu einem Speicherverlust in Programmen werden, die viele kurzlebige Threads starten.

Das Erstellen eines Hash der Bytes von pthread_t (egal ob Struktur oder Zeiger, lange Ganzzahl oder was auch immer) kann eine verwendbare Lösung sein, die keine Nachschlagetabellen erfordert. Wie bei jedem Hash besteht die Gefahr von Kollisionen, Sie können jedoch die Länge des Hashs an Ihre Anforderungen anpassen.

2
Jim

Ich weiß, dieser Thread ist sehr alt. Nachdem Sie alle obigen Beiträge gelesen haben, möchte ich noch eine weitere Idee hinzufügen, um dies auf eine saubere Weise zu behandeln: Wenn Sie trotzdem in das Mapping-Geschäft einsteigen (pthread_to in ein int abbilden), könnten Sie auch einen Schritt weiter gehen Lesbarkeit. Machen Sie Ihren pthread_create_wrapper so, dass er auch eine Zeichenfolge benötigt ... den Namen des Threads. Ich lernte diese "SetThreadName ()" - Funktion unter Windows und Windows CE zu schätzen. Vorteile: Ihre IDs sind nicht nur Zahlen, sondern Sie sehen auch, welcher Ihrer Threads welchen Zweck hat.

1
user2173833

Sie können es in eine vorzeichenlose Kurzform konvertieren und dann nur die letzten vier Hex-Ziffern drucken. Der resultierende Wert kann für Ihre Anforderungen eindeutig genug sein.

1
David R Tribble

Wie James oben erwähnt hat, ist es am besten, sich den Header anzusehen, in dem der Typ definiert ist.

Die Definition von pthread_t finden Sie in pthreadtypes.h unter:

/usr/include/bits/pthreadtypes.h

0
ymdatta

Nur eine Ergänzung zum ersten Beitrag: Verwenden Sie einen benutzerdefinierten Unionstyp zum Speichern von pthread_t:

union tid {
    pthread_t pthread_id;
    unsigned long converted_id;
};

Wenn Sie pthread_t drucken möchten, erstellen Sie eine tid und weisen Sie tid.pthread_id = ... zu. Drucken Sie dann tid.converted_id.

0
Harold H.