简体   繁体   中英

How to get integer thread id in c++11

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?

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.

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

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

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.

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.

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

I really dont know how fast is this, but this is the solution I managed to guestimate :

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;

Again I'm starting to think that getting a pointer to the structure and casting it to unsigned int or uint64_t is the answer... 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 to prevent hellish problems :) Rewrite is easy compared to hunting down this kind of bug. :)

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

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

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

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.

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

In header file do:

const std::string & ThreadName(const std::string name="");

In src file do:

const std::string & ThreadName(const std::string name)
{
    static std::atomic_int threadCount{0};
    const thread_local std::string _name = name + std::to_string(threadCount.fetch_add(1));
    return _name; 
}

Usage:

void myThread()
{
   ThreadName("myThread"); // Call once at very beginning of your thread creation
   ...
   std::cout << ThreadName() << std::endl; // Anyplace in your code
}

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM