How to print pthread_t

113,501

Solution 1

This will print out a hexadecimal representation of a pthread_t, no matter what that actually is:

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]));
  }
}

To just print a small id for a each pthread_t something like this could be used (this time using 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];
}

Depending on the platform and the actual representation of pthread_t it might here be necessary to define an operator< for pthread_t, because std::map needs an ordering on the elements:

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

Solution 2

GDB uses the thread-id (aka kernel pid, aka LWP) for short numbers on Linux. Try:

  #include <syscall.h>
  ...

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

Solution 3

In this case, it depends on the operating system, since the POSIX standard no longer requires pthread_t to be an arithmetic type:

IEEE Std 1003.1-2001/Cor 2-2004, item XBD/TC2/D6/26 is applied, adding pthread_t to the list of types that are not required to be arithmetic types, thus allowing pthread_t to be defined as a structure.

You will need to look in your sys/types.h header and see how pthread_t is implemented; then you can print it how you see fit. Since there isn't a portable way to do this and you don't say what operating system you are using, there's not a whole lot more to say.

Edit: to answer your new question, GDB assigns its own thread ids each time a new thread starts:

For debugging purposes, gdb associates its own thread number—always a single integer—with each thread in your program.

If you are looking at printing a unique number inside of each thread, your cleanest option would probably be to tell each thread what number to use when you start it.

Solution 4

OK, seems this is my final answer. We have 2 actual problems:

  • How to get shorter unique IDs for thread for logging.
  • Anyway we need to print real pthread_t ID for thread (just to link to POSIX values at least).

1. Print POSIX ID (pthread_t)

You can simply treat pthread_t as array of bytes with hex digits printed for each byte. So you aren't limited by some fixed size type. The only issue is byte order. You probably like if order of your printed bytes is the same as for simple "int" printed. Here is example for little-endian and only order should be reverted (under define?) for big-endian:

#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. Get shorter printable thread ID

In any of proposed cases you should translate real thread ID (posix) to index of some table. But there is 2 significantly different approaches:

2.1. Track threads.

You may track threads ID of all the existing threads in table (their pthread_create() calls should be wrapped) and have "overloaded" id function that get you just table index, not real thread ID. This scheme is also very useful for any internal thread-related debug an resources tracking. Obvious advantage is side effect of thread-level trace / debug facility with future extension possible. Disadvantage is requirement to track any thread creation / destruction.

Here is partial pseudocode example:

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. Just register new thread ID.

During logging call pthread_self() and search internal table if it know thread. If thread with such ID was created its index is used (or re-used from previously thread, actually it doesn't matter as there are no 2 same IDs for the same moment). If thread ID is not known yet, new entry is created so new index is generated / used.

Advantage is simplicity. Disadvantage is no tracking of thread creation / destruction. So to track this some external mechanics is required.

Solution 5

On Centos 5.4 x86_64, pthread_t is a typedef to a unsigned long.

Therefore, we could do this...

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

int main() {
    pthread_t x;
    printf("%li\n", (unsigned long int) x);
    std::cout << (unsigned long int) x << "\n";
}
Share:
113,501
dimba
Author by

dimba

Updated on July 08, 2022

Comments

  • dimba
    dimba almost 2 years

    Searched, but don't come across a satisfying answer.

    I know there's no a portable way to print a pthread_t.

    How do you do it in your app?

    Update:

    Actually I don't need pthread_t, but some small numeric id, identifying in debug message different threads.

    On my system (64 bit RHEL 5.3) it's defined as unsigned long int, so it's big number and just printing it eats a valuable place in debug line. How does gdb assign short tids?

  • dimba
    dimba over 14 years
    +1 for portability. But this solution yields even longer pthread_t representation that it's numeric "non portable" solutions.
  • dimba
    dimba over 14 years
    gdb assignes a short numbers. I'd happy with some similar solution
  • dimba
    dimba over 14 years
    This returns LWP. Maybe I'm wrong but pthread can be bounded at runtime to different LWPs, thus not uniquely identifying different pthreads
  • dimba
    dimba over 14 years
    +1 for lookup table. I also was considering this approach. Although I don't have a controll over all created threads, they all use the same function to print message in logger. So I can build a lookup table at log time.
  • dimba
    dimba over 14 years
    How can I be sure that this 2 bytes are unique over all thread ids?
  • Employed Russian
    Employed Russian over 14 years
    On Linux there is a 1:1 mapping between pthread_t and LWP. You will never get the same thread to report different LWPs at different points in its life time.
  • Admin
    Admin over 14 years
    A thread-local storage variable would also work. You could also hold off on assigning numbers until needed for a given thread, but this is getting into the tradeoffs specific to your program.
  • caf
    caf over 14 years
    R. Pate: No, it doesn't. Note that the ptc pointer is dereferenced in the fprintf line.
  • David R Tribble
    David R Tribble over 14 years
    I said it might be unique enough. You can always truncate to the last N digits, where N is determined experimentally.
  • Jan Hudec
    Jan Hudec over 11 years
    Calling it LWP is IMO wrong on Linux. Because there are no "light" and "heavy" weight processes. There are just tasks, the schedulable entities, that may share various resources. And that's what this Linux-specific system call returns, task id.
  • Pramod
    Pramod about 11 years
    Thanks! Use %lu to avoid warnings with gcc -Wall
  • jww
    jww over 10 years
    James: "your cleanest option would probably be to tell each thread what number to use when you start it" - I just wen through pthread_create, and nothing jumped out at me. How does one do this?
  • James McNellis
    James McNellis over 10 years
    The fourth parameter to pthread_create allows you to pass arbitrary data to the thread procedure.
  • David Schwartz
    David Schwartz over 6 years
    There's no guarantee this will produce a unique value for each thread. In fact, that's specifically why we have functions like pthread_equal.
  • David Schwartz
    David Schwartz over 6 years
    What if each thread has more than one possible pthread_t value that refers to it?
  • fonini
    fonini about 3 years
    What is the purpose of casting to void* before casting to unsigned char*? Why isn't the first cast redundant?