从std::thread::id结构中获取Windows线程标识符

5
我在代码中使用了std::thread::id,需要使用一些原生函数作为ThreadId的参数,该参数必须是Win32 DWORD类型的(与GetCurrentThreadId()返回的值相同)。
我找不到任何方法将std::thread::id转换为Win32 DWORD ThreadId。最接近的是std::thread具有native_handle。但我仍然无法创建std::thread以从std::thread::id获取native_handle,因此我离所需的内容还有很远的距离。
我是否遗漏了什么?还是标准可移植线程函数和本地函数之间的差距太大,以至于标准API对我的目的不可用?

5
他正在与Windows线程系统交互,这也不是必须存在的(按照C++标准),并且也没有可移植的语义。 :) - Yakk - Adam Nevraumont
2
std::thread::id 可以表示它未与任何线程相关联,或者可以标识特定运行的线程。我不明白从 std::thread::id 创建 std::thread 会意味着什么。 - Pete Becker
1
@SergeyA 英特尔? 带有 POSIX 线程的 MinGW-w64? - Yakk - Adam Nevraumont
1
@PeteBecker,没有人会对此提出异议。这是链接:https://msdn.microsoft.com/library/jj870808(v=vs.110).aspx - SergeyA
1
@PeteBecker,不太明白你的意思。这里使用的是MSVC编译器(从注释中可以看出)。文档说明native_handle是Windows线程句柄。还有什么需要讨论的吗? - SergeyA
显示剩余15条评论
3个回答

2
这个答案假设您正在使用MSVC2015中的Microsoft std::thread示例,并且未来的文档事实不会改变。
根据文档,没有办法从std::thread :: id转换为native_handle
您可以尝试维护从std::thread :: idstd::threadnative_handle的表格,但在实践中,这需要一个瓶颈,您可以控制所有std::thread的创建。这似乎有点太多了。
如果测试std::thread :: id整数的值,您会发现它与位中的本机句柄相同。在当前时间。因此,您可以参与相当可怕的未定义行为并提取位并转换为整数。不建议这样做,因为您依赖于Microsoft永远不会更改其实现的非文档详细信息;这是一个等待发生故障和维护的噩梦。
因此,请寻求以不同的方式解决您的问题。直接请求native_handle,或者在没有本地API的情况下解决您的问题。在许多情况下,使用本地API是一个坏迹象;其中一半使用涉及尝试从线程外部挂起或终止线程,这在C++(以及一般情况下)是一个非常糟糕的想法。

3
另一半内容是关于改变线程优先级的,遗憾的是在 C++ 中不可用。 - SergeyA

1
这是一种特定于RTL实现的方法,可以从std::thread::id获取内部线程ID表示,详见这里
// 
#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;
}

最初错误地称其为“GetThreadHandle”,但由于它对于MSC而言不正确,因此更名。 - Vladimir Ulchenko

0
你可以在 Visual C++ 中轻松获取 Windows 线程标识符。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();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接