Как распечатать pthread_t
Искал, но не нашел удовлетворительного ответа.
Я знаю, что нет портативного способа печати pthread_t.
Как вы это делаете в своем приложении?
Обновление:
На самом деле мне не нужен pthread_t, но некоторый небольшой числовой идентификатор, идентифицирующий в отладочном сообщении разные потоки.
В моей системе (64-битная RHEL 5.3) она определяется как unsigned long int, поэтому она имеет большое количество и просто печатает, что она ест ценное место в строке отладки. Как gdb назначает короткие тиды?
Ответы
Ответ 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