cprogrammer
cprogrammer

Reputation: 5675

Retrieve the Windows thread identifier from the std::thread::id structure

I have access to a std::thread::id in my code, and need to use some native functions that receive as argument ThreadId as DWORD ( same as returned by GetCurrentThreadId() ).

I cannot find any way to convert from std::thread::id to a Win32 DWORD ThreadId. The closest thing I can find is std::thread has that has a native_handle. But I still have no way to create the std::thread to get the native_handle from a std::thread::id, so I am still too far from what I need.

Is there something that I am missing? Or is the gap between standard portable thread functions and native functions so big that the standard api is unusable for my purposes?

Upvotes: 5

Views: 2987

Answers (3)

Vladimir Ulchenko
Vladimir Ulchenko

Reputation: 463

here's rtl implementation specific approach to get internal thread id representation from std::thread::id, see here

// 
#include <iostream>
#include <thread>

#ifdef _WIN32
#include <Windows.h>
#endif

namespace ns
{
    struct dummy{};
    using thread_id_access=std::basic_ostream<dummy>;
}

namespace std
{
    template <>
    class basic_ostream<ns::dummy>
    {
    public:
#if defined(_WIN32)
        using id_type=unsigned int;
#elif defined(_GLIBCXX_RELEASE)         
        using id_type=std::thread::native_handle_type;
#else
    #error Consult your rtl implementation
#endif            
        id_type id=0;
    };
    
    template<>
    ns::thread_id_access & operator <<(ns::thread_id_access & os, std::thread::id id) 
    {
#if defined(_GLIBCXX_RELEASE)         
        os.id=id._M_thread;
#elif defined(_MSC_VER)        
        os.id=id._Id;
#else
    #error Consult your rtl implementation        
#endif        
        return os;
    }
}

namespace ns
{
    inline auto GetThreadId(std::thread::id id)
    {
        thread_id_access t;
        t<<id;
        return t.id;    
    }
}

int main() 
{
    auto const id=std::this_thread::get_id();
    std::cout<<std::hex<<id<<"\n";
    std::cout<<std::hex<<ns::GetThreadId(id)<<"\n";
 #ifdef _WIN32   
    std::cout<<GetCurrentThreadId()<<"\n";
#endif    
    return 0;
}

Upvotes: 1

CoolCmd
CoolCmd

Reputation: 1047

You can easily get the Windows thread identifier, at least in Visual C++. std::thread::native_handle() returns a Win32 thread handle, and the Win32 API function GetThreadId() returns a thread identifier:

#include <thread>

void stopGUIThread(std::thread& guiThread)
{
    if (guiThread.joinable())
    {
        auto threadId = ::GetThreadId(guiThread.native_handle());
        assert(threadId != 0);
        // PostThreadMessage() will return 0 if the thread has
        // already finished its execution.
        ::PostThreadMessage(threadId, WM_QUIT, 0, 0);
        guiThread.join();
    }
}

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

This answer will presume you are using microsofts std::thread example from MSVC2015, and that documented facts about it will not change in the future.

There is no way to go from std::thread::id to native_handle under the docs.

You could attempt to maintain a table from std::thread::id to std::thread or native_handles, but that in practice requires a bottleneck where you can control all std::thread creation. Which seems a bit much.

If you test the value of the std::thread::id integer, you'll find it is the same as the native handle in bits at the current time. So you can engage in rather horrible undefined behavior and extract the bits and convert to an integer. Doing so is not advised, as you are relying that microsoft never changes its non-documented details of its implementation; it is a bug and maintenance nightmare waiting to happen.

So seek to solve your problem a different way. Request native_handles directly, or solve your problem without the native APIs. In many cases use of native APIs is a bad sign; half of such use involves attempting to suspend or terminate a thread from outside the thread, which is a really really bad idea in C++ (and in general, really).

Upvotes: 2

Related Questions