This tip shows a side effect of GetCurrentThread and explains what to do when you need to avoid that.
Introduction
When you need to get a handle to the current thread, you can use GetCurrentThread
which gives you a pseudo handle which you don't need to close because it is not a real reference counted handle. This is mentioned clearly in the documentation. However, I recently bumped my head against this. I wanted to share it so that others can avoid having to chase this down.
My Headbump
Consider the following example:
DWORD worker(void* ctx)
{
std::cout << "Thread id: " << GetThreadId((HANDLE)ctx) << std::endl;
return 0;
}
int main()
{
HANDLE hMainThread = GetCurrentThread();
std::cout << "Thread id: " << GetThreadId(hMainThread) << std::endl;
HANDLE hThread = CreateThread(NULL, 0, worker, hMainThread, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
}
This is what happens:
Without thinking, I had assumed that the pseudo handle was just a weak copy of the actual handle (a non reference counted copy of the current handle), and I could reference it in a worker thread. Instead, it is a special constant that literally means 'when this handle value is supplied, use the current thread'. And if you pass that special value to another thread, then that value will translate to the thread handle of 'that' thread.
If you read the documentation, then this is exactly what it says. Only I didn't stop to think about what that actually meant.
Getting the Real Thread Handle
If you want to get a real handle that you can pass to another thread, do this:
HANDLE hMainThread = NULL;
if (!DuplicateHandle(
GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&hMainThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS)) {
cout << "Error " << GetLastError() << " cannot duplicate main handle." << endl;
return GetLastError();
}
Of course, when you do this, you get a HANDLE
value that you do need to close when you no longer need it.
Points of Interest
As I said, this is nothing earth shattering and the documentation explains this. However, it took me a while before I understood why my APCs were scheduled in the wrong thread, so perhaps I can save others the trouble. :)
History
- 27th December, 2022: First version