Thread Handle Query
-
Hi, I have a multi-threaded OCX (MFC) - which spawns 5 worker threads at a time, for a list of jobs. I am using
WaitForMultipleObjects()
with the handles of the 5 threads to wait until any of the thread finishes. As soon asWaitForMultipleObjects()
returns, that thread is reused for the next job in the queue. I need to know how do I check if the handle of a given thread is valid or not! When a given thread "ends", its handle is NOT alwaysNULL
, and so cannot be checked as:if(m_pthJob[nItr]->m_hThread == NULL)
Could you please guide me how to check if the handle is valid or invalid? Thanks, Nirav Doshi * Don't wish it was easier, wish you were better! * -
Hi, I have a multi-threaded OCX (MFC) - which spawns 5 worker threads at a time, for a list of jobs. I am using
WaitForMultipleObjects()
with the handles of the 5 threads to wait until any of the thread finishes. As soon asWaitForMultipleObjects()
returns, that thread is reused for the next job in the queue. I need to know how do I check if the handle of a given thread is valid or not! When a given thread "ends", its handle is NOT alwaysNULL
, and so cannot be checked as:if(m_pthJob[nItr]->m_hThread == NULL)
Could you please guide me how to check if the handle is valid or invalid? Thanks, Nirav Doshi * Don't wish it was easier, wish you were better! *When you create a thread, you get a handle back. That handle remains valid until you explicitly close it (or your process exits, but by that time it's too late to use the handle). The handle remains valid even after the thread exits, because the thread object in the kernel doesn't go away until all handles on it are closed. When a thread exits, your handles don't magically become null. If your handle is becoming invalid (is
WaitForMultipleObjects()
returning an error?) then you're doing something else wrong with the handles. --Mike-- Personal stuff:: Ericahist | Homepage Shareware stuff:: 1ClickPicGrabber | RightClick-Encrypt CP stuff:: CP SearchBar v2.0.2 | C++ Forum FAQ ---- I even hear the Windows "OMG I booted up fine" sound. -- Paul Watson diagnosing hardware problems. -
When you create a thread, you get a handle back. That handle remains valid until you explicitly close it (or your process exits, but by that time it's too late to use the handle). The handle remains valid even after the thread exits, because the thread object in the kernel doesn't go away until all handles on it are closed. When a thread exits, your handles don't magically become null. If your handle is becoming invalid (is
WaitForMultipleObjects()
returning an error?) then you're doing something else wrong with the handles. --Mike-- Personal stuff:: Ericahist | Homepage Shareware stuff:: 1ClickPicGrabber | RightClick-Encrypt CP stuff:: CP SearchBar v2.0.2 | C++ Forum FAQ ---- I even hear the Windows "OMG I booted up fine" sound. -- Paul Watson diagnosing hardware problems.Michael Dunn wrote: If your handle is becoming invalid (is WaitForMultipleObjects() returning an error?) Yes! I'll explain here: Suppose I have 12 jobs. Since my
MAX_THREADS
is 5, 7 jobs are pending the first timeWaitForMultipleObjects()
is called. As and when myWaitForMultipleObjects()
returns, I get back to assigning another job to that (returned) thread. I have another small loop just before callingWaitForMultipleObjects()
where I an checking if by the time I was assigning another job to the first thread that returned, if any other thread has finished. To find if any other thread has finished working till I am assigning another job, I am checking if the thread handle is valid/invalid. Here I am getting the thread handle sometimes asNULL (0x00000000)
or some junk (0xfeeeeeee
, etc.) so I am unable to check for it. I have another method (which I didn't really like!), which is using a thread variable to give the current thread state. But I hope, there's some way to check if the thread handle is valid/invalid. Thanks, Nirav Doshi * Don't wish it was easier, wish you were better! * -
Hi, I have a multi-threaded OCX (MFC) - which spawns 5 worker threads at a time, for a list of jobs. I am using
WaitForMultipleObjects()
with the handles of the 5 threads to wait until any of the thread finishes. As soon asWaitForMultipleObjects()
returns, that thread is reused for the next job in the queue. I need to know how do I check if the handle of a given thread is valid or not! When a given thread "ends", its handle is NOT alwaysNULL
, and so cannot be checked as:if(m_pthJob[nItr]->m_hThread == NULL)
Could you please guide me how to check if the handle is valid or invalid? Thanks, Nirav Doshi * Don't wish it was easier, wish you were better! *How are you starting your threads? If you are using AfxBeginThread (and looking at m_pthJob[nItr]->m_hThread, it looks if you are), I suspect you are being plauged by MFC's auto deleting thread system. Make sure you set the m_bAutoDelete member of the returned thread to FALSE before starting the thread (create it in a suspeded state). The thread handle will then remaing valid, even after the thread is finished. If it is running, WaitForSingleObject(hThread, 0) will give you WAIT_OBJECT_0, if not, it will give you WAIT_TIMEOUT. Remeber to then delete your CWinThread's manually Or, use DuplicateHanlde to copy the m_hThread handle from the real WinThread to someewhere else - then clean up using CloseHandle.
-
How are you starting your threads? If you are using AfxBeginThread (and looking at m_pthJob[nItr]->m_hThread, it looks if you are), I suspect you are being plauged by MFC's auto deleting thread system. Make sure you set the m_bAutoDelete member of the returned thread to FALSE before starting the thread (create it in a suspeded state). The thread handle will then remaing valid, even after the thread is finished. If it is running, WaitForSingleObject(hThread, 0) will give you WAIT_OBJECT_0, if not, it will give you WAIT_TIMEOUT. Remeber to then delete your CWinThread's manually Or, use DuplicateHanlde to copy the m_hThread handle from the real WinThread to someewhere else - then clean up using CloseHandle.
Hello Diddy, You're right about the thread being deleted automatically since I'm not setting the AutoDelete flag to FALSE! But I was doing it expecting the thread handle to be set to NULL when the thread finished - or something which gave me a response that the thread is done working. So, how would I then get to know if a thread is not running ((hopefully) without using a variable/flag)? I need to check if a given thread is currently finished or still working. Thanks, Nirav * Don't wish it was easier, wish you were better! *
-
Hello Diddy, You're right about the thread being deleted automatically since I'm not setting the AutoDelete flag to FALSE! But I was doing it expecting the thread handle to be set to NULL when the thread finished - or something which gave me a response that the thread is done working. So, how would I then get to know if a thread is not running ((hopefully) without using a variable/flag)? I need to check if a given thread is currently finished or still working. Thanks, Nirav * Don't wish it was easier, wish you were better! *
To check if a thread is running: CWinThread* pThread = .... if(::WaitForSingleObject(pThread->m_hThread, 0) == WAIT_OBJECT_0)) { // thread is running } else { // thread has finished } The other way is also: if(::GetExitCodeThread(pThread->m_hThread, &dwExit) != 0 && dwExit == STILL_ACTIVE) { // thread is running } else { // thread has finished } But the first is usually prefered. With both, you must be careful you are working with a valid thread handle. FYI there are 2 ways (that i know of) to be sure you have a vaid handle with MFC threads: Autodelete - default --------------------- CWinThread* pThread = ::AfxBeginThread(...); This way, as you have discovered, you can't do anything with the pThread as MFC can delete it at any time. After the above thread has been started, doing pThread-> is ALWAYS a risky bit of code. You don't know when MFC will kill off your CWinThread object, and you could be refering to a bit of memory that has just been deleted. DuplicateHandle ---------------- CWinThread* pThread = ::AfxBeginThread(...CREATE_SUSPENDED); HANDLE h; ::DuplicateHandle(pThread->m_hThread, h, ...); This works because handles are refrenced counted. The DuplicateHanld call bumps this count up to 2 and puts a copy in 'h', so when CWinThread autodeletes and does a CloseHandle on it's m_hThread member, the handle isn't realy closed until you do a CloseHandle on 'h'. Don't be tempted to do this: CWinThread* pThread = ::AfxBeginThread(...CREATE_SUSPENDED); HANDLE h = pThread->m_hThread; As your count will still only be at 1. m_bAutoDelete = FALSE; ---------------------- As shown above, this is usually the easiest. Just delete your CWinThread* and that will close your thread handle.
-
To check if a thread is running: CWinThread* pThread = .... if(::WaitForSingleObject(pThread->m_hThread, 0) == WAIT_OBJECT_0)) { // thread is running } else { // thread has finished } The other way is also: if(::GetExitCodeThread(pThread->m_hThread, &dwExit) != 0 && dwExit == STILL_ACTIVE) { // thread is running } else { // thread has finished } But the first is usually prefered. With both, you must be careful you are working with a valid thread handle. FYI there are 2 ways (that i know of) to be sure you have a vaid handle with MFC threads: Autodelete - default --------------------- CWinThread* pThread = ::AfxBeginThread(...); This way, as you have discovered, you can't do anything with the pThread as MFC can delete it at any time. After the above thread has been started, doing pThread-> is ALWAYS a risky bit of code. You don't know when MFC will kill off your CWinThread object, and you could be refering to a bit of memory that has just been deleted. DuplicateHandle ---------------- CWinThread* pThread = ::AfxBeginThread(...CREATE_SUSPENDED); HANDLE h; ::DuplicateHandle(pThread->m_hThread, h, ...); This works because handles are refrenced counted. The DuplicateHanld call bumps this count up to 2 and puts a copy in 'h', so when CWinThread autodeletes and does a CloseHandle on it's m_hThread member, the handle isn't realy closed until you do a CloseHandle on 'h'. Don't be tempted to do this: CWinThread* pThread = ::AfxBeginThread(...CREATE_SUSPENDED); HANDLE h = pThread->m_hThread; As your count will still only be at 1. m_bAutoDelete = FALSE; ---------------------- As shown above, this is usually the easiest. Just delete your CWinThread* and that will close your thread handle.
Thank you very much Diddy for taking the efforts to explain this! :rose::-O I've taken note about your
DuplicateHandle()
point! Thanks! I'm now changing a majority of my processor code & logic. I guess, using a variable which gives me the current state of each of my threads is the best work-around for my problem. :doh: Working on it...:~ Thanks again to you and Micheal for your replies.:cool: Hope I could be able to help you both here someday! - Nirav Doshi * Don't wish it was easier, wish you were better! * -
Thank you very much Diddy for taking the efforts to explain this! :rose::-O I've taken note about your
DuplicateHandle()
point! Thanks! I'm now changing a majority of my processor code & logic. I guess, using a variable which gives me the current state of each of my threads is the best work-around for my problem. :doh: Working on it...:~ Thanks again to you and Micheal for your replies.:cool: Hope I could be able to help you both here someday! - Nirav Doshi * Don't wish it was easier, wish you were better! *