Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

The Current Thread Handle

5.00/5 (5 votes)
27 Dec 2022MIT1 min read 15.9K  
What to do when you want to use the current thread handle
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:

C++
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:

C++
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

License

This article, along with any associated source code and files, is licensed under The MIT License