5

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?

cprogrammer
  • 5,503
  • 3
  • 36
  • 56
  • Why is `native_handle` not sufficient for you? – Holt Apr 26 '16 at 13:15
  • @Holt - maybe because `native_handle` is not required to exist, and if it does, it has no portable semantics? Keep in mind that the meaning and possible uses of `native_handle_type` are implementation defined. – Pete Becker Apr 26 '16 at 13:17
  • 5
    @PeteBecker He is interacting with the windows threading system, which is also not required to exist (by the C++ standard), and has no portable semantics either. :) – Yakk - Adam Nevraumont Apr 26 '16 at 13:18
  • 2
    `std::thread::id` can indicate that it is not associated with any thread, or it can identify a particular running thread. I don't see what it would mean to `create `std::thread` from `std::thread::id`. – Pete Becker Apr 26 '16 at 13:19
  • @Yakk - if you know you're on Windows, you can use the Windows threading stuff. There is no requirement that a C++ implementation on Windows implement `native_handle` or that, if it does, `native_handle_type` has any direct connection with the Windows threading stuff. There's an additional step from "running on Windows" to "using `native_handle_type`, and that step is implementation defined; it is not portable across implementations that run on Windows. – Pete Becker Apr 26 '16 at 13:22
  • @Holt native_handle is available only for current thread. That is not may case – cprogrammer Apr 26 '16 at 13:25
  • @Pete I am on Windows and very important (and forgot to mention) I am using Vs2015. I cannot re-implement everything using WinApi, I only have access to std::thread::id and I need to use some Windows specific code ... – cprogrammer Apr 26 '16 at 13:28
  • @PeteBecker I would want to create std::thread` from std::thread::id, because std::thread has `native_handle` and from there I have a connection with Windows Api. – cprogrammer Apr 26 '16 at 13:36
  • 1
    @PeteBecker, you are unneccessary pedantic. I know of one fully thread-enabled compiler implementations on Windows, and it does provide a native_handle as a type suitable for Windows threading API. – SergeyA Apr 26 '16 at 13:38
  • 1
    @SergeyA [Intel](https://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler)? [MinGW-w64 with POSIX threads](http://stackoverflow.com/a/19425966/1774667)? – Yakk - Adam Nevraumont Apr 26 '16 at 13:42
  • @Yakk, I totally forgot about Intel :). Never seen it in my life. And yes, forgot that MinGW64 as well - since never used it either. My experience on Windows is limited to MSVC and MinGW gcc.On a side note, read about Intel support for C+14. Phew.... And they charge money for this? – SergeyA Apr 26 '16 at 13:45
  • @SergeyA - you're missing the point. Yes, implementations provide `native_handle` and, yes, those implementations provide `native_handle_type` that's "suitable" for Windows threading. Nevertheless, the **content** of that object and the **uses** you can put it to are implementation defined. There is no requirement that it be a particular type or that you can make particular Windows API calls with it. In practice that means that when you compile code that uses `native_handle` you have to read the compiler's documentation to see what you can do with it. – Pete Becker Apr 26 '16 at 13:56
  • 1
    @PeteBecker, no one argues about it. And here you go: https://msdn.microsoft.com/library/jj870808(v=vs.110).aspx – SergeyA Apr 26 '16 at 14:12
  • @SergeyA - um, yes, Microsoft tells you what **their implementation** does. Try it this: assume you're compiling for Windows, and assume that `native_handle` and `native_handle_type` both exist for the compiler that you're using. Show me some portable code that uses `native_handle_type`. – Pete Becker Apr 26 '16 at 14:13
  • 1
    @PeteBecker, not following you. This is MSVC compiler, which is used here (from the comments). Doc states native_handle to be the Windows thread handle. What else is here to discuss? – SergeyA Apr 26 '16 at 14:22
  • @SergeyA - if your definition of **portable** code is "whatever Microsoft says they do", there is, indeed, nothing to discuss. What started things down this rathole was various responses to my assertion that using 'native_handle()` is not portable. Nothing you've said has any bearing on that. – Pete Becker Apr 26 '16 at 14:30
  • 1
    @PeteBecker The OP question is not about "portable code", but explicitly about "VS2015 on Windows". We here talk about very speciifc implementation. OP is prepared to a implementation-defined solution, and even explicitly asks for it. Thus I don't really see what are you arguing about here. – Ilya Popov Apr 26 '16 at 14:35
  • @IlyaPopov - you should read the question again. It doesn't say **anything** about "VS2015 on Windows". That came out in a comment that was made **after** my comment. We here talk about what is actually said, not retroactively insisting that later comments make previous ones wrong. Using `native_handle_type` is not portable, and that **should** be a concern for anyone who considers using it. – Pete Becker Apr 26 '16 at 14:55
  • 1
    @PeteBecker In the very first sentence it says "and need to use some native functions that receive as argument ThreadId as DWORD ( same as returned by GetCurrentThreadId() )". That means the OP is *already* in the implementation-specific territory. – Ilya Popov Apr 26 '16 at 14:59
  • @IlyaPopov - sigh. Yes, code that targets the Windows API is, obviously, not portable to other OSes. But even when you restrict yourself to the Windows API, code that uses `native_handle_type` is not portable, because different **compilers** that target the same OS can and do have different definitions of it. – Pete Becker Apr 26 '16 at 15:08

3 Answers3

2

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

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

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

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();
    }
}
CoolCmd
  • 939
  • 8
  • 13