113

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?

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 13
    What do you need it to be an integer for? It is guaranteed not to make sense to do arithmetic of any sort on it, and it's not meaningful outside the context of the process, so there should be no need to serialize it other than for debugging (which the `operator<<` seems to handle fine). – hmakholm left over Monica Sep 15 '11 at 14:07
  • 4
    something like this:http://www.1024cores.net/home/lock-free-algorithms/false-sharing---false but instead of N=MAX_THREAD_COUNT I will have something like N=128 and do thread_id%N – NoSenseEtAl Sep 15 '11 at 14:11
  • 9
    If you really want it to be portable, then you need to be prepared for the possibility that `thread::id` isn't represented as an integer at all. The page you link to uses an array, indexed by thread ID. Have you considered using a `map` instead? Then you can use the relational operators already defined for the `id` class without doing any conversions. The standard also defines `hash`, so you can use the unordered containers, too. – Rob Kennedy Sep 15 '11 at 15:07
  • 4
    @Rob that map would require mutexing :( – NoSenseEtAl Sep 15 '11 at 15:20
  • @NoSenseEtAl Maybe just read write lock that lazily add to the map missing values (the next ID). – selalerer Sep 15 '11 at 15:23
  • well still slow(AFAIK, could be wrong), but maybe I'm wrong. If you can produce example as an answer and prove me wrong that would be great. I mean original point is to remove hotspot, now I introduce another to get the distributed mutexes... :) Again I could be wrong – NoSenseEtAl Sep 15 '11 at 15:52
  • So imagine thread_id is castable, what would you do with an integer like 139918771783456? Uae it as an index in an array? Good luck with that. – n. m. could be an AI Jan 03 '18 at 09:26
  • If - which is probably the use case for the majority - you just want to get the thread id for dumping and logging and tracing purposes, instead of writing: ``std::to_string(std::this_thread::get_id())``, I, for one on windows find writing: ``::GetCurrentThreadId()`` much less harming to my old fingers. So if you don't care about portability, screw the standard, which tries to force you into using ugly ``iostream`` for that purpose. – BitTickler Jun 24 '19 at 12:17
  • @NoSenseEtAI, if you're still around: do you want the int thread ID to be unique for the life of the program? If so, most of the answers--all the ones based on get_id()--won't work as once a thread dies the get_id() value may be reused for a new thread. – Swiss Frank Apr 14 '20 at 15:52
  • 1
    @SwissFrank or should I say CHF :P I am still around, but I think the accepted answer is ok for me, it is up to me to make sure that variable id values are unique for the duration of a program. – NoSenseEtAl Apr 14 '20 at 16:12
  • I haven't been referred to as CHF in 15+ years! Anyway, my point is that if you really wanted the IDs to be unique per thread, and not just unique per currently-existing-thread, most of the answers here would have to be commented as not being solutions... – Swiss Frank Apr 14 '20 at 16:18
  • @NoSenseEtAl You can use `std::hash` on `std::thread::id` to obtain "more or less unique" value from thread id. This is not ideal, but is guaranteed to work in case thread id itself is not an integer. And it should work fine in your `id % N` case. – Marandil Dec 01 '21 at 15:50
  • see also https://stackoverflow.com/a/74832738/119609 – Vladimir Ulchenko Dec 17 '22 at 14:46

11 Answers11

119

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.

Dev Null
  • 4,731
  • 1
  • 30
  • 46
888
  • 3,246
  • 8
  • 41
  • 60
  • 41
    I think this has to be `std::hash()(std::this_thread::get_id())`, doesn't it? – Barry May 13 '13 at 20:38
  • 15
    Would the hash be guaranteed unique? Probably not, defeating its use as a unique thread identifier. – Michael Goldshteyn Sep 04 '13 at 19:26
  • Michael Goldshteyn it is not, but from the comments it is clear that my usage is a bit specific... – NoSenseEtAl Mar 04 '14 at 12:07
  • 2
    The example as given doesn't work with at least Clang 3.4 and libstdc++ 4.8. Barry's reformulation does work, however. – Arto Bendiken Mar 30 '14 at 13:36
  • 3
    thanks 888 for the answer. MS compiler does have thread::id::hash() but Barry's code is standards compliant. Hashes can collide. It's yet useful to have a hash per thread (with hopefully a collision probability near 0) – a.lasram Jan 22 '15 at 22:04
  • 1
    MSVC actually returns a **hashed** thread id in this case. You might as well generate your own... – rustyx Oct 03 '17 at 14:34
37

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.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • 1
    Aha! But there *is* a text representation! That's good enough for humans to visually find distinction between them, right? – Xunie Aug 18 '16 at 12:11
  • The thread::id (or this_thread::get_id()) solution mentioned here is best, because it's not programmer-specific. See Mike's stringstream answer below to get a string or integer representation. – Andrew Feb 12 '17 at 00:36
  • @Andrew I addressed that in the answer: "Even its text representation produced by operator<< is unspecified, so you can't rely on it being the representation of a number". Seems like a shady definition of the word "best" is at hand. – R. Martinho Fernandes Feb 13 '17 at 06:17
  • "best" was not in relation to the string representation. – Andrew Feb 13 '17 at 13:23
  • 2
    Also, I just did a benchmark with 10,000,000 iterations for my own sake and this_thread::get_id() is wicked fast: http://pastebin.com/eLa3rKQE Debug mode takes 0.0000002543827 seconds per call and Release takes 0.00000003652367 seconds per call for me. (Intel i5 2.60 GHz) – Andrew Feb 14 '17 at 05:33
  • @R.MartinhoFernandes The `std::async` would never return until `work_item()` finishes its work.Maybe you need a `vector` alike to store the returned value. How do you think about it? – John Oct 09 '22 at 01:53
36

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...

Mike
  • 607
  • 7
  • 8
  • 2
    Good answer. This would serve the purpose in general. – iammilind Dec 14 '14 at 06:02
  • 5
    This is not portable, as there's no guarantee that a `std::thread::id` prints as characters that make up an integer in much the same way that it's not guaranteed that the thread id is internally represented by an integer. – blubberdiblub Jun 24 '17 at 06:28
  • 1
    @Nikos whenever an implementation chooses that an integer is insufficient. Or whenever it deems it inappropriate for any other reason. The point here is that when the specification doesn't specify it as an integer (and it doesn't, it just has some more abstract guarantees), you cannot and should not rely on it being an integer in any implementation. Simply use `std::thread::id` as type instead of some integer, that's what it exists for. And don't reinterpret its string representation as digits making up a number. Treat it as opaque or as debugging/logging output. – blubberdiblub Sep 17 '19 at 10:29
  • @blubberdiblub that's arguing out of the ivory tower of highest C++ abstraction. But as this the such born thread id is quite useless by design. All OSs I know count threads with numbers. For those the number *is* the expected value. And even every output of other OSs thread ids could always be represented as unambiguous number – V15I0N Aug 05 '22 at 06:54
  • @blubberdiblub On Windows `std::thread::id` is clearly defined as unsigned int. `using _Thrd_id_t = unsigned int; struct _Thrd_t { // thread identifier for Win32 void* _Hnd; // Win32 HANDLE _Thrd_id_t _Id; };` So i think all OS used number to represents a thread id. – Kenny Apr 18 '23 at 14:53
  • @Kenny you're kinda missing my point, though. Even if all current popular **implementations** use an integer to represent a thread ID, it's still not portable. Any C++ implementation can choose to implement the thread ID as trivially copyable type of data, not just one of the native integers. It's also not the OS that's really important here (although it could exact some influence on the implementation of the particular compiler, of course), but the specific variant of C++ compiler you're using. There's not just Visual C++ on Windows; you can have almost any other C++ compiler on Windows, too. – blubberdiblub Apr 18 '23 at 21:11
10

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.

Dev Null
  • 4,731
  • 1
  • 30
  • 46
tgoodhart
  • 3,111
  • 26
  • 37
  • 1
    `pthread_self()` actually returns a `pthread_t`, which is opaque (unlike `pid_t` (returned by `gettid()`) which, while also platform-specific, is apparently an integer, at least). But +1 for the first bit, it solved my problem! – Cameron Aug 23 '13 at 04:56
8

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.

midjji
  • 394
  • 3
  • 9
6

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.

6502
  • 112,025
  • 15
  • 165
  • 265
  • @NoSenseEtAl: Not sure I understand your question... `thread_local` already describes the storage duration for `tid`. The `static` for `thread_counter` is because you don't want to expose it outside this compilation unit. – 6502 Sep 18 '19 at 08:23
  • This kind of weirdly assigns thread IDs in the order you query thread ID. (I've done something VERY similar myself, and I never liked this weirdness.) It also assigns from zero, which isn't usual. (For instance GDB reports thread IDs starting at 1.) – Swiss Frank Apr 14 '20 at 15:49
  • 1
    @SwissFrank: it's just a number and you shouldn't read too much in the value returned: there's no legal way to know that it was assigned when you queried it :-) . About the fact that `0` is a valid ID that is a good point and can be fixed using preincrement instead. I'll change the answer to do that. – 6502 Apr 14 '20 at 16:23
  • 1
    For the right use case, e.g., a reasonably finite number of threads, a logging system, and a human using it who prefers things like '1' and '2' instead of 0x7e8000499000 or 140141742282496, this is just a ridiculously elegant solution. – Allan Bazinet Jan 21 '21 at 13:40
  • I use something very similar: `int GetThreadId() { static std::atomic_int threadCount{0}; thread_local int threadId = threadCount.fetch_add(1); return threadId; }` You can init `threadCount` to any value you like (e.g. `1`). – abufct Sep 19 '21 at 14:48
5

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

Federico Rizzo
  • 183
  • 2
  • 9
  • Nice, but why do you assume it is an integer? It can be hex or anything else. – rustyx Oct 03 '17 at 15:18
  • if you are using `std::stringstream`, then you can use its `operator >>` to convert to int. I'd actually prefer `uint64_t` as type of `id` instead of `int` if I am sure that the `id` is integral. – aniliitb10 Dec 07 '19 at 10:09
4

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).

Alexey Polonsky
  • 1,141
  • 11
  • 12
  • 1
    Where is it specified that `std::thread::native_handle_type` is a typedef for `long unsigned`? In 30.3.1/1 we can only see `typedef implementation-defined native_handle_type; // See 30.2.3` – Ruslan Apr 25 '18 at 13:48
  • A dumb but simple way to discover the type is to generate a deliberate compilation error by assigning thread::native_handle() to e.g. uint8_t. Then the compiler will complain about type mismatch and will also tell you what the type is. – Alexey Polonsky Apr 26 '18 at 15:04
  • 1
    Well that's non-portable since it relies on particular implementation. – Ruslan Apr 26 '18 at 15:35
  • Well, at least if the underlying implementation uses POSIX pthread, it seems that native_handle() must be a pthread_t. Now, pthread_t is a pointer type (typedef struct pthread * pthread_t). So, it makes sense that std::thread::native_handle_type is an integer type capable of containing a pointer (e.g. size_t or unsigned long). – Alexey Polonsky Apr 29 '18 at 12:49
2

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.

Pandrei
  • 4,843
  • 3
  • 27
  • 44
  • 1
    The overloaded `operator<<` can print *anything*, it is wrong to assume it will always print an integer. – rustyx Oct 03 '17 at 15:19
1

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];
}
geh
  • 836
  • 6
  • 11
0

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.

Random typ
  • 45
  • 5
  • This is just `reinterpret_cast<>`'ing the thread::id value as an unsigned int, which assumes that the underlying representation is an unsigned int (or usefully interpreted as such), but that isn't guaranteed. – dmattp Aug 29 '23 at 16:53