Как получить целочисленный идентификатор потока в С++ 11
С++ 11 имеет возможность получения текущего идентификатора потока, но он не поддается целочисленному типу:
cout<<std::this_thread::get_id()<<endl;
: 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
error: недопустимый листинг из типа 'std:: thread:: id для ввода' uint64_t
такие же для других типов:
invalid cast from type 'std:: thread:: id для ввода' uint32_t
Я действительно не хочу делать кастинг с указателем, чтобы получить идентификатор целочисленного потока. Есть ли разумный способ (стандартный, потому что я хочу, чтобы он был переносимым), чтобы сделать это?
Ответы
Ответ 1
Портативное решение - передать ваши собственные идентификаторы в поток.
int id = 0;
for(auto& work_item : all_work) {
std::async(std::launch::async, [id,&work_item]{ work_item(id); });
++id;
}
Тип std::thread::id
должен использоваться только для сравнения, а не для арифметики (т.е. как сказано на банке: идентификатор). Даже его текстовое представление, созданное operator<<
, не указано, поэтому вы не можете полагаться на то, что оно представляет собой число.
Вы также можете использовать карту значений std::thread::id
для своего собственного идентификатора и поделиться этой картой (с надлежащей синхронизацией) между потоками, а не передавать идентификатор напрямую.
Ответ 2
Вам просто нужно сделать
std::hash<std::thread::id>{}(std::this_thread::get_id())
чтобы получить size_t
.
Из контекста:
Специализация шаблона std::hash
для std::thread::id
позволяет пользователям получать хэши идентификаторов потоков.
Ответ 3
Другим id (идея? ^^) будет использование stringstreams:
std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());
И используйте try catch, если вы не хотите, чтобы исключение было в случае, если все пошло не так...
Ответ 4
Одной из идей было бы использовать локальное хранилище потоков для хранения переменной - не имеет значения, какой тип, если он соответствует правилам локального хранилища потоков, - затем использовать адрес этой переменной как свой "идентификатор потока" ". Очевидно, любая арифметика не будет иметь смысла, но она будет интегральным типом.
Для потомков:
pthread_self()
возвращает a pid_t
и является posix. Это переносимо для определения портативного устройства.
gettid()
, почти наверняка не переносимый, но он возвращает дружественное значение GDB.
Ответ 5
Я действительно не знаю, как быстро это происходит, но это решение, которое мне удалось выполнить:
const size_t N_MUTEXES=128;//UINT_MAX,not 128 for answer to my original question
hash<std::thread::id> h;
cout<<h(std::this_thread::get_id())%N_MUTEXES<<endl;
Снова я начинаю думать, что получить указатель на структуру и отбросить ее к unsigned int или uint64_t - это ответ...
EDIT:
uint64_t get_thread_id()
{
static_assert(sizeof(std::thread::id)==sizeof(uint64_t),"this function only works if size of thead::id is equal to the size of uint_64");
auto id=std::this_thread::get_id();
uint64_t* ptr=(uint64_t*) &id;
return (*ptr);
}
int main()
{
cout<<std::this_thread::get_id()<<" "<<get_thread_id()<<endl;
}
static_assert для предотвращения адских проблем:) Переписывать легко по сравнению с поиском такого рода ошибок.:)
Ответ 6
Таким образом, следует работать:
std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());
Не забудьте включить библиотеку sstream
Ответ 7
thread::native_handle()
возвращает thread::native_handle_type
, который является typedef для long unsigned int
.
Если поток создан по умолчанию, native_handle() возвращает 0. Если к нему присоединен поток ОС, возвращаемое значение ненулевое (это pthread_t в POSIX).
Ответ 8
это зависит от того, для чего вы хотите использовать thread_id;
вы можете использовать:
std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());
Это создаст уникальный идентификатор с вашим процессом; но есть ограничение: если вы запускаете несколько экземпляров одного и того же процесса, и каждый из них записывает свои идентификаторы потоков в общий файл, уникальность thread_id не гарантируется; на самом деле, скорее всего, у вас будут перекрытия.
В этом случае вы можете сделать что-то вроде:
#include <sys/time.h>
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;
теперь вам гарантируются уникальные идентификаторы потоков по всей стране.
Ответ 9
Может быть, это решение будет полезным для кого-то. Назовите это впервые im main()
. Предупреждение: names
растет бесконечно.
std::string currentThreadName(){
static std::unordered_map<std::thread::id,std::string> names;
static std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx);
auto id = std::this_thread::get_id();
if(names.empty()){
names[id] = "Thread-main";
} else if(names.find(id) == names.end()){
std::stringstream stream;
stream << "Thread-" << names.size();
names[id] = stream.str();
}
return names[id];
}
Ответ 10
Другая альтернатива:
#include <atomic>
static std::atomic<unsigned long long> thread_counter;
unsigned long long thread_id() {
thread_local unsigned long long tid = thread_counter++;
return tid;
}
Сгенерированный код для этой функции g++ в 64-разрядной версии x86 просто:
_Z9thread_idv:
cmp BYTE PTR fs:[email protected], 0
je .L2
mov rax, QWORD PTR fs:[email protected]
ret
.L2:
mov eax, 1
lock xadd QWORD PTR _ZL14thread_counter[rip], rax
mov BYTE PTR fs:[email protected], 1
mov QWORD PTR fs:[email protected], rax
ret
_ZGVZ9thread_idvE3tid:
.zero 8
_ZZ9thread_idvE3tid:
.zero 8
Т.е. одна ветвь без какой-либо синхронизации, которая будет правильно предсказана, за исключением первого вызова функции. После этого просто один доступ к памяти без синхронизации.
Ответ 11
Основная причина не использовать thread :: get_id() заключается в том, что он не уникален для отдельной программы/процесса. Это потому, что идентификатор может быть повторно использован для второго потока, как только первый поток завершится.
Это кажется ужасной особенностью, но это то, что в С++ 11.