Как распечатать pthread_t - PullRequest
       41

Как распечатать pthread_t

48 голосов
/ 19 ноября 2009

Искал, но не нашел удовлетворительного ответа.

Я знаю, что нет портативного способа напечатать pthread_t.

Как вы делаете это в своем приложении?

Обновление:

На самом деле мне не нужен pthread_t, но есть небольшой числовой идентификатор, идентифицирующий в отладочном сообщении разные потоки.

В моей системе (64-битный RHEL 5.3) он определен как unsigned long int, так что это большое число, и просто его печать занимает ценное место в строке отладки. Как GDB назначает короткие приливы?

Ответы [ 11 ]

32 голосов
/ 19 ноября 2009

Это выведет шестнадцатеричное представление pthread_t, независимо от того, что это на самом деле:

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

Чтобы просто напечатать небольшой идентификатор для каждого pthread_t, можно использовать что-то вроде этого (на этот раз с помощью 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];
}

В зависимости от платформы и фактического представления pthread_t здесь может потребоваться определить operator< для pthread_t, поскольку для std::map требуется упорядочение элементов:

bool operator<(const pthread_t &left, const pthread_t &right) {
  ...
}
23 голосов
/ 19 ноября 2009

GDB использует идентификатор потока (он же pid ядра, он же LWP) для коротких номеров в Linux. Попробуйте:

  #include <syscall.h>
  ...

    printf("tid = %d\n", syscall(SYS_gettid));
14 голосов
/ 19 ноября 2009

В этом случае это зависит от операционной системы, поскольку стандарт POSIX больше не требует, чтобы pthread_t был арифметическим типом :

IEEE Std 1003.1-2001 / Cor 2-2004, применяется элемент XBD / TC2 / D6 / 26, добавляя pthread_t в список типов, которые не обязательно должны быть арифметическими, что позволяет определяется как структура.

Вам нужно заглянуть в заголовок sys/types.h и увидеть, как реализован pthread_t; тогда вы можете распечатать его так, как считаете нужным. Поскольку не существует переносимого способа сделать это, и вы не говорите, какую операционную систему вы используете, сказать больше нечего.

Редактировать: , чтобы ответить на ваш новый вопрос, GDB назначает свои собственные идентификаторы потоков при каждом запуске нового потока :

В целях отладки gdb связывает свой собственный номер потока - всегда одно целое число - с каждым потоком в вашей программе.

Если вы смотрите на печать уникального номера внутри каждой нити, ваш самый чистый вариант, вероятно, будет указывать каждой нити, какой номер использовать при запуске.

7 голосов
/ 19 ноября 2009

ОК, кажется, это мой окончательный ответ. У нас есть 2 актуальные проблемы:

  • Как получить более короткие уникальные идентификаторы для потока для регистрации.
  • В любом случае нам нужно вывести реальный идентификатор pthread_t для потока (просто для ссылки на значения POSIX как минимум).

1. Печать идентификатора POSIX (pthread_t)

Вы можете просто рассматривать pthread_t как массив байтов с шестнадцатеричными цифрами, напечатанными для каждого байта. Таким образом, вы не ограничены каким-либо типом фиксированного размера. Единственная проблема - порядок байтов. Вам, вероятно, понравится, если порядок ваших напечатанных байтов такой же, как и для простого напечатанного «int». Вот пример для байтов с прямым порядком байтов, и только порядок должен быть возвращен (при определении?) Для байтов с прямым порядком байтов:

#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. Получите более короткую нить для печати ID

В любом из предложенных случаев вы должны перевести реальный идентификатор потока (posix) в индекс некоторой таблицы. Но есть 2 существенно разных подхода:

2,1. Отслеживать темы.

Вы можете отслеживать ID потоков всех существующих потоков в таблице (их вызовы pthread_create () должны быть обернуты) и иметь «перегруженную» функцию id, которая дает вам только индекс таблицы, а не идентификатор реального потока. Эта схема также очень полезна для любой внутренней отладки, связанной с отслеживанием ресурсов. Очевидным преимуществом является побочный эффект средства трассировки / отладки на уровне потоков с возможным будущим расширением. Недостатком является требование отслеживать создание / удаление любого потока.

Вот пример частичного псевдокода:

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. Просто зарегистрируйте новый идентификатор темы.

Во время регистрации вызывайте pthread_self () и ищите внутреннюю таблицу, если она знает поток. Если поток с таким идентификатором был создан, его индекс используется (или повторно используется из ранее созданного потока, на самом деле это не имеет значения, поскольку на тот же момент нет двух одинаковых идентификаторов). Если идентификатор потока еще не известен, создается новая запись, поэтому генерируется / используется новый индекс.

Преимущество - простота. Недостатком является отсутствие отслеживания создания / уничтожения потоков. Поэтому для отслеживания этого требуется некоторая внешняя механика.

4 голосов
/ 19 ноября 2009

В Centos 5.4 x86_64 pthread_t является typedef для беззнакового long.

Следовательно, мы могли бы сделать это ...

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

int main() {
    pthread_t x;
    printf("%li\n", (unsigned long int) x);
    std::cout << (unsigned long int) x << "\n";
}
3 голосов
/ 10 августа 2012

, если pthread_t - просто число; это было бы самым простым.

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

    int * threadid = (int *) (void *) &tid;
    return *threadid;
}
3 голосов
/ 19 ноября 2009

Вы можете сделать что-то вроде этого:

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

Если вы можете положиться на GCC (в этом случае также работает clang), вы также можете сделать это:

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

Если ваша платформа поддерживает это, аналогичная опция:

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

Это имеет то преимущество, что вам не нужно передавать thread_id в вызовах функций, но это не работает, например. в Mac OS.

2 голосов
/ 30 ноября 2012

Таблица поиска (pthread_t : int) может стать утечкой памяти в программах, запускающих множество недолговечных потоков.

Создание хеша байтов pthread_t (будь то структура или указатель, длинное целое число или что-то еще) может быть полезным решением, которое не требует таблиц поиска. Как и для любого хеша, существует риск коллизий, но вы можете настроить длину хеша в соответствии с вашими требованиями.

1 голос
/ 16 апреля 2013

Я знаю, эта тема очень старая. Прочитав все вышеупомянутые посты, я хотел бы добавить еще одну идею для аккуратного решения этой проблемы: В любом случае, если вы попадаете в картографический бизнес (отображая pthread_to в int), вы можете сделать еще один шаг вперед в удобочитаемости. Сделайте ваш pthread_create_wrapper таким, чтобы он тоже принимал строку ... имя потока. Я научился ценить эту функцию «SetThreadName ()» в Windows и Windows CE. Преимущества: ваши идентификаторы - это не просто цифры, но вы также видите, какая из ваших тем имеет какое назначение.

1 голос
/ 19 ноября 2009

Вы можете попробовать преобразовать его в беззнаковое короткое замыкание, а затем распечатать только последние четыре шестнадцатеричных числа. Полученное значение может быть достаточно уникальным для ваших нужд.

...