从 std::thread::id 结构中检索 Windows 线程标识符



我可以访问代码中的std::thread::id,并且需要使用一些本机函数,这些函数作为参数ThreadId作为DWORD接收(与GetCurrentThreadId()返回的相同)。

我找不到任何从std::thread::id转换为Win32 DWORD线程ID的方法。 我能找到的最接近的东西是std::thread有一个native_handle。 但是我仍然没有办法创建从std::thread::id获得native_handle std::thread,所以我离我需要的还是太远了。

我缺少什么吗? 还是标准可移植线程函数和本机函数之间的差距太大,以至于标准 API 无法用于我的目的?

此答案将假定您使用的是 Microsoft std::thread MSVC2015 示例中的示例,并且有关它的记录事实将来不会更改。

文档下没有办法从std::thread::id转到native_handle

您可以尝试将表从 std::thread::id 维护到 std::threadnative_handle 秒,但这实际上需要一个瓶颈,您可以在其中控制所有std::thread创建。 这似乎有点多。

如果测试std::thread::id整数的值,您会发现它与当前本机句柄(以位为单位)相同。 因此,您可以进行相当可怕的未定义行为并提取位并转换为整数。 不建议这样做,因为您依赖 Microsoft 永远不会更改其未记录的实现细节;这是一个等待发生的错误和维护噩梦。

因此,寻求以不同的方式解决问题。 直接请求native_handle,或者在没有本机 API 的情况下解决问题。 在许多情况下,使用本机 API 是一个不好的迹象;这种使用中有一半涉及尝试从线程外部挂起或终止线程,这在C++中是一个非常非常糟糕的主意(一般来说,真的)。

这是从 std::thread::id 获取内部线程 ID 表示形式的 RTL 实现特定方法,请参见此处

// 
#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;
}

您可以轻松获取 Windows 线程标识符,至少在 Visual C++ 中是这样。 std::thread::native_handle()返回 Win32 线程句柄,Win32 API 函数GetThreadId()返回线程标识符:

#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();
    }
}

最新更新