如何在 c + + 11中得到整数线程 id

C + + 11有获得当前线程 id 的可能性,但它不能转换为整数类型:

cout<<std::this_thread::get_id()<<endl;

产出: 139918771783456

cout<<(uint64_t)std::this_thread::get_id()<<endl;

Error: 从‘ std: : thread: : id’类型转换为‘ uint64 _ t’类型无效 其他类型也一样: 从‘ std: : thread: : id’类型转换为‘ uint32 _ t’类型无效

我真的不想做指针强制转换得到整数线程 id。是否有一些合理的方法(标准的,因为我希望它是可移植的)来做到这一点?

130256 次浏览

The portable solution is to pass your own generated IDs into the thread.

int id = 0;
for(auto& work_item : all_work) {
std::async(std::launch::async, [id,&work_item]{ work_item(id); });
++id;
}

The std::thread::id type is to be used for comparisons only, not for arithmetic (i.e. as it says on the can: an identifier). Even its text representation produced by operator<< is unspecified, so you can't rely on it being the representation of a number.

You could also use a map of std::thread::id values to your own id, and share this map (with proper synchronization) among the threads, instead of passing the id directly.

One idea would be to use thread local storage to store a variable - doesn't matter what type, so long as it complies with the rules of thread local storage - then to use the address of that variable as your "thread id". Obviously any arithemetic will not be meaningful, but it will be an integral type.

For posterity: pthread_self() returns a pid_t and is posix. This is portable for some definition of portable.

gettid(), almost certainly not portable, but it does return a GDB friendly value.

You just need to do

std::hash<std::thread::id>{}(std::this_thread::get_id())

to get a size_t.

From cppreference:

The template specialization of std::hash for the std::thread::id class allows users to obtain hashes of the identifiers of threads.

Another id (idea? ^^) would be to use stringstreams:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

And use try catch if you don't want an exception in the case things go wrong...

it depends on what you what you want to use the thread_id for; you can use:

std::stringstream ss;
ss << std::this_thread::get_id();
uint64_t id = std::stoull(ss.str());

This will generate a unique id withing you process; but there's a limitation: if you launch several instances of the same process and each one of them writes their thread ids to a common file, the uniqueness of the thread_id is not guaranteed; in fact it's very likely you'll have overlaps. In this case you can do something like:

#include <sys/time.h>
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t id = (ts.tv_sec % 1000000000) * 1000000000 + ts.tv_nsec;

now you are guaranteed unique thread ids systemwide.

In this way, should work:

std::stringstream ss;
ss << std::this_thread::get_id();
int id = std::stoi(ss.str());

Remember to include library sstream

thread::native_handle() returns thread::native_handle_type, which is a typedef to long unsigned int.

If thread is default constructed, native_handle() returns 0. If there is an OS thread attached to it, the return value is non-zero (it is pthread_t on POSIX).

Maybe this solution be helpful to someone. Call it a first time im main(). Warning: names grows indefinitely.

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

A key reason not to use thread::get_id() is that it isn't unique for in a single program/process. This is because the id can be reused for a second thread, once the first thread finishes.

This seems like a horrible feature, but its whats in c++11.

Another alternative:

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

The generated code for this function by g++ in x86 64-bit is just:

_Z9thread_idv:
cmp     BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 0
je      .L2
mov     rax, QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff
ret
.L2:
mov     eax, 1
lock xadd       QWORD PTR _ZL14thread_counter[rip], rax
mov     BYTE PTR fs:_ZGVZ9thread_idvE3tid@tpoff, 1
mov     QWORD PTR fs:_ZZ9thread_idvE3tid@tpoff, rax
ret
_ZGVZ9thread_idvE3tid:
.zero   8
_ZZ9thread_idvE3tid:
.zero   8

I.e. a single branch without any synchronization that will be correctly predicted except for the first time you call the function. After that just a single memory access without synchronization.

You actually can do it with casting too:

std::thread::id threadId = std::this_thread::get_id();
unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<void*>(&threadId));

I compared casting, std::hash and std::stringstream on a million iterations and found that std::hash is the fastest solution with a time of 1293500ns while casting is only 11ms slower with 1384200ns and std::stringstream as the slowest at std::hash0.