Подтвердить что ты не робот

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

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

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

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

Обновление:

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

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

4b9b3361

Ответ 1

Это выведет шестнадцатеричное представление 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) {
  ...
}

Ответ 2

GDB использует thread-id (aka kernel pid, aka LWP) для коротких номеров в Linux. Попробуйте:

  #include <syscall.h>
  ...

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

1. Печать POSIX ID (pthread_t)

Вы можете просто обрабатывать pthread_t как массив байтов с шестнадцатеричными цифрами, напечатанными для каждого байта. Таким образом, вы не ограничены каким-то фиксированным типом. Единственная проблема - порядок байтов. Вероятно, вам понравится, если порядок ваших напечатанных байтов будет таким же, как и для простого "int". Вот пример для little-endian и только порядок должен быть возвращен (под define?) Для 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. Получить более короткий идентификатор потока для печати

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

2.1. Отслеживайте темы.

Вы можете отслеживать идентификаторы потоков всех существующих потоков в таблице (их вызовы 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() и найдите внутреннюю таблицу, если она знает поток. Если поток с таким идентификатором был создан, его индекс используется (или повторно используется из предыдущего потока, на самом деле это не имеет значения, поскольку в тот же момент нет двух одинаковых идентификаторов). Если идентификатор потока еще не известен, создается новая запись, поэтому создается и используется новый индекс.

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

Ответ 5

В Centos 5.4 x86_64 pthread_t является typedef для unsigned 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";
}

Ответ 6

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

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.

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

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

Ответ 10

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

Ответ 11

Просто добавление к первому сообщению: используйте определенный пользователем тип объединения для хранения pthread_t:

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

Всякий раз, когда вы хотите напечатать pthread_t, создайте tid и назначьте tid.pthread_id = ..., затем распечатайте tid.converted_id.

Ответ 12

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

Вы можете найти определение pthread_t в pthreadtypes.h, который можно найти по адресу:

/usr/include/bits/pthreadtypes.h