我可以访问代码中的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::thread
或 native_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();
}
}