locked
How to use the thread handle when replacing Windows CreateThread with std::thread? RRS feed

  • Question

  • Hi,

    We have the below code that was written using CreateThread.

    HANDLE       m_hReceiveThread ;

    void CUPSData::createUPSThread() { m_hReceiveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceiveDataFromUPS,(LPVOID)this, NULL, NULL); if (NULL != m_hReceiveThread) { printToUPSFile(UPS_LOG_INFO, " receive thread started");

    } else { printToUPSFile(UPS_LOG_ERROR, " Unable to start receive thread"); g_bUPSFail = true; } }

    void CUPSData::ReceiveDataFromUPS(LPVOID f_data) { printToUPSFile(UPS_LOG_INFO, "Start"); CUPSData *l_hclassInstance = (CUPSData *)f_data;

    f_data->receiveData(); }


    I was asked to replace CreateThread with std::thread. Using std::thread, I am writing like as shown below:

    std::thread(ReceiveDataFromUPS, this);

    But, when replacing Windows CreateThread with std::thread, how to use the HANDLE (m_hReceiveThread) as this handle is using in many other places. 

    for eg, this handle is using in other function like (DWORD dwWaitResult = WaitForSingleObject(m_hReceiveThread, INFINITE);

    Could someone please help me with their inputs?

    Regards,

    Monday, June 29, 2020 12:59 PM

Answers

  • Thank you all for your inputs:

    Based on your inputs, I changed the code like as shown below:

    std::thread      m_hReceiveThread;

    void CUPSData::createUPSThread()
    {	
    m_hReceiveThread = std::thread(ReceiveDataFromUPS, this);
    if (m_hReceiveThread.joinable())
    {		
    printToUPSFile(UPS_LOG_INFO, " receive thread started");	}	
    else	
    {		
    printToUPSFile(UPS_LOG_ERROR, " Unable to start receive thread");		
    g_bUPSFail = true;	
    }
    }

    Read the documentation for the constructor of a thread object carefully.  What happens if the constructor fails to create a thread?  Hint -- think exceptions.  Do you need to test for success with joinable()?

    I am also using m_hReceiveThread in the below function.

    Here, I replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    if(m_hReceiveThread.joinable()) { DWORD l_exitCode = NULL; /////////Waiting to thread successfully closed

    GetExitCodeThread(m_hReceiveThread, &l_exitCode); if (l_exitCode == STILL_ACTIVE) { // Replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    m_hReceiveThread.native_handle(); if (m_hReceiveThread.native_handle() == WAIT_OBJECT_0)

    { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Return :WAIT_OBJECT_0");

    }

    else { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Failed");

    } } if (CloseHandle(m_hReceiveThread)) { printToUPSFile(UPS_LOG_INFO "Successfully ThreadHandle Closed"); } m_hReceiveThread = NULL; }


    This doesn't make sense.  In your example, m_hReceiveThread is a std::thread object.  A call to m_hReceiveThread.native_handle() returns the HANDLE of the underlying Windows thread.

    Why would you think that m_hReceiveThread.native_handle() is equivalent to WaitForSingleObject?

    Did you even try to compile this code?

    How to use std::thread variable with GetExitCodeThread Windows function?
    How to use std::thread variable with CloseHandle Windows function?
    And also how to set the std::thread variable with NULL?


    GetExitCodeThread requires a HANDLE.  We already showed you how to obtain a HANDLE from a std::thread object.

    Why would you ever want to call CloseHandle when working with std::thread?  Same question for setting it to NULL.  If you want to know if a std::thread object has an associated thread then look at https://docs.microsoft.com/en-us/cpp/standard-library/thread-class?view=vs-2019#get_id


    • Marked as answer by David student Tuesday, June 30, 2020 3:57 PM
    Monday, June 29, 2020 5:58 PM
  • Here, I replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    I'm curious as to how you decided that this is what you should do. Where did you get the idea that m_hReceiveThread.native_handle() was equivalent to WaitForSingleObject(reinterpret_cast<HANDLE>(m_hReceiveThread.native_handle()), INFINITE) or even m_hReceiveThread.join()?

    Read the documentation or even the post you are directly replying to. It helps if you understand what you are doing if you use these libraries.

    How to use std::thread variable with GetExitCodeThread Windows function?

    Well, since the native_handle member function is clearly documented to return the thread's HANDLE on Windows:

    std::thread my_thread = /*initialise the thread*/;
    DWORD exit_code = 0;
    
    GetExitCodeThread(reinterpret_cast<HANDLE>(my_thread.native_handle()), &exit_code);

    is obvious, right?

    How to use std::thread variable with CloseHandle Windows function?

    You don't this is wrapped in the thread object and destroyed when the variable goes out of scope or a new thread assigned.

    And also how to set the std::thread variable with NULL?

    You don't this is wrapped in the thread object and cleaned up when the variable goes out of scope or a new thread assigned.

    But as already mentioned, you must call join or detach on the thread object before it goes out of scope or you reassign it.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, June 29, 2020 6:09 PM

All replies

  • You should always use the documentation to answer this kind of question.

    As an example, the documentation gives this.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, June 29, 2020 1:02 PM
  • See https://docs.microsoft.com/en-us/cpp/standard-library/thread-class?view=vs-2019#native_handle

    Also, when using std::thread you must call std::thread.join() before the std::thread object goes out of scope and its destructor runs unless you first detach the Windows thread from the std:: thread object by calling std::thread.detach().

    Monday, June 29, 2020 1:09 PM
  • Instead of a member variable of type HANDLE, you'd have a member variable of type std::thread.

    WaitForSingleObject(m_hReceiveThread, INFINITE) is replaced by m_myThread.join()

    That's pretty much the only thing you can do with std::thread - wait for it to finish. If the current code is using m_hReceiveThread for anything more complicated than that, you'd need to use m_myThread.native_handle()


    Igor Tandetnik

    Monday, June 29, 2020 2:45 PM
  • Thank you all for your inputs:

    Based on your inputs, I changed the code like as shown below:

    std::thread      m_hReceiveThread;

    void CUPSData::createUPSThread()
    {	
    m_hReceiveThread = std::thread(ReceiveDataFromUPS, this);
    if (m_hReceiveThread.joinable())
    {		
    printToUPSFile(UPS_LOG_INFO, " receive thread started");	}	
    else	
    {		
    printToUPSFile(UPS_LOG_ERROR, " Unable to start receive thread");		
    g_bUPSFail = true;	
    }
    }
    I am also using m_hReceiveThread in the below function.

    Here, I replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    if(m_hReceiveThread.joinable()) { DWORD l_exitCode = NULL; /////////Waiting to thread successfully closed

    GetExitCodeThread(m_hReceiveThread, &l_exitCode); if (l_exitCode == STILL_ACTIVE) { // Replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    m_hReceiveThread.native_handle(); if (m_hReceiveThread.native_handle() == WAIT_OBJECT_0)

    { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Return :WAIT_OBJECT_0");

    }

    else { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Failed");

    } } if (CloseHandle(m_hReceiveThread)) { printToUPSFile(UPS_LOG_INFO "Successfully ThreadHandle Closed"); } m_hReceiveThread = NULL; }

    From the above function, Please help me: 

    How to use std::thread variable with GetExitCodeThread Windows function?
    How to use std::thread variable with CloseHandle Windows function?
    And also how to set the std::thread variable with NULL?

    Monday, June 29, 2020 4:34 PM
  • Thank you all for your inputs:

    Based on your inputs, I changed the code like as shown below:

    std::thread      m_hReceiveThread;

    void CUPSData::createUPSThread()
    {	
    m_hReceiveThread = std::thread(ReceiveDataFromUPS, this);
    if (m_hReceiveThread.joinable())
    {		
    printToUPSFile(UPS_LOG_INFO, " receive thread started");	}	
    else	
    {		
    printToUPSFile(UPS_LOG_ERROR, " Unable to start receive thread");		
    g_bUPSFail = true;	
    }
    }

    Read the documentation for the constructor of a thread object carefully.  What happens if the constructor fails to create a thread?  Hint -- think exceptions.  Do you need to test for success with joinable()?

    I am also using m_hReceiveThread in the below function.

    Here, I replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    if(m_hReceiveThread.joinable()) { DWORD l_exitCode = NULL; /////////Waiting to thread successfully closed

    GetExitCodeThread(m_hReceiveThread, &l_exitCode); if (l_exitCode == STILL_ACTIVE) { // Replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    m_hReceiveThread.native_handle(); if (m_hReceiveThread.native_handle() == WAIT_OBJECT_0)

    { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Return :WAIT_OBJECT_0");

    }

    else { printToUPSFile(UPS_LOG_INFO, "WaitForSingleObject Failed");

    } } if (CloseHandle(m_hReceiveThread)) { printToUPSFile(UPS_LOG_INFO "Successfully ThreadHandle Closed"); } m_hReceiveThread = NULL; }


    This doesn't make sense.  In your example, m_hReceiveThread is a std::thread object.  A call to m_hReceiveThread.native_handle() returns the HANDLE of the underlying Windows thread.

    Why would you think that m_hReceiveThread.native_handle() is equivalent to WaitForSingleObject?

    Did you even try to compile this code?

    How to use std::thread variable with GetExitCodeThread Windows function?
    How to use std::thread variable with CloseHandle Windows function?
    And also how to set the std::thread variable with NULL?


    GetExitCodeThread requires a HANDLE.  We already showed you how to obtain a HANDLE from a std::thread object.

    Why would you ever want to call CloseHandle when working with std::thread?  Same question for setting it to NULL.  If you want to know if a std::thread object has an associated thread then look at https://docs.microsoft.com/en-us/cpp/standard-library/thread-class?view=vs-2019#get_id


    • Marked as answer by David student Tuesday, June 30, 2020 3:57 PM
    Monday, June 29, 2020 5:58 PM
  • Here, I replaced WaitForSingleObject with m_hReceiveThread.native_handle()

    I'm curious as to how you decided that this is what you should do. Where did you get the idea that m_hReceiveThread.native_handle() was equivalent to WaitForSingleObject(reinterpret_cast<HANDLE>(m_hReceiveThread.native_handle()), INFINITE) or even m_hReceiveThread.join()?

    Read the documentation or even the post you are directly replying to. It helps if you understand what you are doing if you use these libraries.

    How to use std::thread variable with GetExitCodeThread Windows function?

    Well, since the native_handle member function is clearly documented to return the thread's HANDLE on Windows:

    std::thread my_thread = /*initialise the thread*/;
    DWORD exit_code = 0;
    
    GetExitCodeThread(reinterpret_cast<HANDLE>(my_thread.native_handle()), &exit_code);

    is obvious, right?

    How to use std::thread variable with CloseHandle Windows function?

    You don't this is wrapped in the thread object and destroyed when the variable goes out of scope or a new thread assigned.

    And also how to set the std::thread variable with NULL?

    You don't this is wrapped in the thread object and cleaned up when the variable goes out of scope or a new thread assigned.

    But as already mentioned, you must call join or detach on the thread object before it goes out of scope or you reassign it.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, June 29, 2020 6:09 PM