Reputation: 30128
c++11 has a possibility of getting current thread id, but it is not castable to integer type:
cout<<std::this_thread::get_id()<<endl;
output : 139918771783456
cout<<(uint64_t)std::this_thread::get_id()<<endl;
error: invalid cast from type ‘std::thread::id’ to type ‘uint64_t’ same for other types: invalid cast from type ‘std::thread::id’ to type ‘uint32_t’
I really dont want to do pointer casting to get the integer thread id. Is there some reasonable way(standard because I want it to be portable) to do it?
Upvotes: 122
Views: 171584
Reputation: 1
namespace std::this_thread
{
inline _NODISCARD uint32_t get_id_2() noexcept
{
thread_local static const auto THIS_THREAD_ID = []()->uint32_t { std::stringstream ss; ss << std::this_thread::get_id(); return std::stoul(ss.str()); }();
return THIS_THREAD_ID;
}
}
Upvotes: 0
Reputation: 61047
thread::id
is just a wrapper around the platform type. For all intents and purposes it's is going to be an unsigned 32-bit integer. So go ahead and treat it as an unsigned 32-bit integer.
Now, if someone is writing code for some exotic platform where this is not the case, then test for this as you move to a new platform. The answers provided thus far are so far removed from what's actually going on here that they make me wanna gouge my eyes out.
static_assert(alignof(std::thread::id) == 4, "uh-oh!");
static_assert(sizeof(std::thread::id) == 4, "uh-oh!");
unsigned thread_id() {
auto id = std::this_thread::get_id();
return *(unsigned *)&id;
}
I get why they wanted to make it a distinct type but this is just annoying we have better things to do than to argue whether this is in line with the standard or not.
Upvotes: 1
Reputation: 65
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 351701200ns.
Upvotes: 1
Reputation: 114579
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.
Upvotes: 6
Reputation: 417
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.
Upvotes: 10
Reputation: 846
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];
}
Upvotes: 1
Reputation: 1211
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).
Upvotes: 5
Reputation: 3266
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.
Upvotes: 11
Reputation: 3416
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 thestd::thread::id
class allows users to obtain hashes of the identifiers of threads.
Upvotes: 133
Reputation: 302
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
Upvotes: 6
Reputation: 4961
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.
Upvotes: 2
Reputation: 647
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...
Upvotes: 39
Reputation: 234644
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.
Upvotes: 38