Search code examples
c++multithreadingc++11stdthread

Standard C++ Thread IDs - strange behavior


i need to create some threads on demand because i dont know before how much i need. To 'store' the threads im using a vector std::vector<std::thread> threads; every time i create a new thread i push them back on the vector: threads.push_back(std::thread(worker));

to store (for testing) the thread id i use the following: double test = std::hash<std::thread::id>()(std::this_thread::get_id()); according to the cpp-references hash, thread::id and get_id this should work fine.

but only with this line im getting as id always a 0 (zero)

if id add the following line below the hash line it works and i get a hashed id from the thread: std::thread::id tid = std::this_thread::get_id(); even i dont use tid

can someone explain this behavior? im working with eclipse juno and cleaned + rebuild the project several times...i just dont get it :/

here the code: (line by line because those format rules here are stupid -.-

std::vector<std::thread> threads;
void worker (){
    double test = std::hash<std::thread::id>()(std::this_thread::get_id());
    std::thread::id tid = std::this_thread::get_id();
    printf("%ld\n", test);
}
void joinThreads(std::thread& t)
{
    t.join();
}
int main() {
    for (int i = 0; i < 10; ++i) {
        threads.push_back(std::thread(worker) );
    }
    std::for_each(threads.begin(),threads.end(),joinThreads);
    return 0;
}

Solution

  • On x86_64 a double argument to printf would be passed in a different register to a long argument, so when you call printf("%ld\n", test) the compiler puts test in a floating point register and calls the function. The printf implementation then looks for the argument in a non-floating point register because the "%ld" conversion specifier tells it to expect a long int argument. Because the actual argument is not in the same register as printf looks in, it fails to find the value.

    When you add the next line it causes the value of tid to be in a non-floating point register, and apparently that allows printf to find it (but don't rely on that, it's undefined behaviour and unpredictable.)

    Solution: If you can't use printf correctly then don't use it at all. Either use the right conversion specified for double i.e. "%f" or store the value in a different type, or use iostreams.