Discussion:
Worker thread ending
(too old to reply)
Newsgroupie
2008-01-20 13:25:50 UTC
Permalink
Hello,

I create a worker thread(s) which will usually run until I tell it to
stop, which I do by signalling a CEvent object which the thread will
see and drop out of the thread function.

However, sometimes the thread my drop out early because it has
completed its tasks or an error has occurred.

When I create this thread I retain a copy of its handle so that after
I have set the stop event I can pass the handle to
WaitForMultipleObject (along with several other thread handles) and
wait for the thread to complete (as it may spend some time tidying a
few things up between it being told to stop and it actually
finishing).

But when the thread finishes prematurely the handle is no longer valid
and so WaitForMultipleObject fails with a GetLastError of 6 (invalid
handle).

I always have the thread set to auto delete. The stop CEvent is not
deleted with the thread.

Can someone please suggest a better way for me to do this sort of
thing so that I can cleanly and safely detect that a running thread
has stopped and that previously running threads have also stopped.

I suppose what I really need to find out is if a thread handle is
still valid?

Many thanks in advance,

'Newsgroupie'
Scott McPhillips [MVP]
2008-01-20 16:28:11 UTC
Permalink
Post by Newsgroupie
Hello,
I create a worker thread(s) which will usually run until I tell it to
stop, which I do by signalling a CEvent object which the thread will
see and drop out of the thread function.
However, sometimes the thread my drop out early because it has
completed its tasks or an error has occurred.
When I create this thread I retain a copy of its handle so that after
I have set the stop event I can pass the handle to
WaitForMultipleObject (along with several other thread handles) and
wait for the thread to complete (as it may spend some time tidying a
few things up between it being told to stop and it actually
finishing).
But when the thread finishes prematurely the handle is no longer valid
and so WaitForMultipleObject fails with a GetLastError of 6 (invalid
handle).
I always have the thread set to auto delete. The stop CEvent is not
deleted with the thread.
There are two approaches to doing this. The first is to turn off auto
delete when the thread starts. That keeps the handle valid even after the
thread has exited. The other approach is to use a message instead of the
handle. The last thing the thread would do before exiting is to post a
message to the main window.
--
Scott McPhillips [VC++ MVP]
Alexander Grigoriev
2008-01-20 17:49:25 UTC
Permalink
If you use MFC, the only proper way to create a thread is to call
AfxBeginThread and create is SUSPENDED, set bAutoDelete to FALSE, and then
call ResumeThread(). This way, the CThread object (and the thread handle in
it) will stay valid after the thread is gone. You'll need to delete it by
yourself. Setting bAutoDelete to TRUE by default was a braindead decision in
the CTread class design.

Another braindead function is _beginthread(). It closes the handle
automatically upon exit. You should use _beginthreadex, if you write plain
C/C++ code (not using MFC).
Post by Newsgroupie
Hello,
I create a worker thread(s) which will usually run until I tell it to
stop, which I do by signalling a CEvent object which the thread will
see and drop out of the thread function.
However, sometimes the thread my drop out early because it has
completed its tasks or an error has occurred.
When I create this thread I retain a copy of its handle so that after
I have set the stop event I can pass the handle to
WaitForMultipleObject (along with several other thread handles) and
wait for the thread to complete (as it may spend some time tidying a
few things up between it being told to stop and it actually
finishing).
But when the thread finishes prematurely the handle is no longer valid
and so WaitForMultipleObject fails with a GetLastError of 6 (invalid
handle).
I always have the thread set to auto delete. The stop CEvent is not
deleted with the thread.
Can someone please suggest a better way for me to do this sort of
thing so that I can cleanly and safely detect that a running thread
has stopped and that previously running threads have also stopped.
I suppose what I really need to find out is if a thread handle is
still valid?
Many thanks in advance,
'Newsgroupie'
Doug Harrison [MVP]
2008-01-20 17:53:54 UTC
Permalink
Post by Newsgroupie
Hello,
I create a worker thread(s) which will usually run until I tell it to
stop, which I do by signalling a CEvent object which the thread will
see and drop out of the thread function.
However, sometimes the thread my drop out early because it has
completed its tasks or an error has occurred.
When I create this thread I retain a copy of its handle so that after
I have set the stop event I can pass the handle to
WaitForMultipleObject (along with several other thread handles) and
wait for the thread to complete (as it may spend some time tidying a
few things up between it being told to stop and it actually
finishing).
But when the thread finishes prematurely the handle is no longer valid
and so WaitForMultipleObject fails with a GetLastError of 6 (invalid
handle).
I always have the thread set to auto delete.
And that's the problem. You're allowing the thread to auto-delete, but you
merely copied the handle instead of using DuplicateHandle on it. (NB: Using
DuplicateHandle isn't the best way; see the web page I link to below for
more on that.)
Post by Newsgroupie
The stop CEvent is not
deleted with the thread.
Can someone please suggest a better way for me to do this sort of
thing so that I can cleanly and safely detect that a running thread
has stopped and that previously running threads have also stopped.
Waiting on the thread handle is the only way to reliably tell if a thread
has completely stopped. (Well, there's also GetExitCodeThread, but it's
superfluous if you don't need the exit code, and it's subject to false
negatives for threads that are careless about their return codes.) You just
need to prevent the handle invalidation. For more on that, and in general
how to use CWinThread safely and deal with all these things, see:

http://members.cox.net/doug_web/threads.htm
Post by Newsgroupie
I suppose what I really need to find out is if a thread handle is
still valid?
No. If you need to use a handle, you never allow it to become invalid. It's
as simple as that.
--
Doug Harrison
Visual C++ MVP
David Lowndes
2008-01-20 18:54:05 UTC
Permalink
Post by Newsgroupie
But when the thread finishes prematurely the handle is no longer valid
Why isn't it valid? The thread handle should be valid until you
explicitly call CloseHandle on it. The fact that the thread has
finished should not be invalidating the thread handle.
Post by Newsgroupie
I always have the thread set to auto delete.
What do you mean by that?

Dave
Newsgroupie
2008-01-20 19:39:50 UTC
Permalink
Thank you for all your advice, guys. You have certainly helped me out.

I now create the thread suspended, set auto delete to FALSE, resume
the thread and at the end of the day after signalling a stop and
waiting for the handle to trigger I delete the thread.

'Newsgroupie'
Joseph M. Newcomer
2008-01-22 22:56:05 UTC
Permalink
CWinThread will do the CloseHandle automatically unless m_bAutoDelete is set FALSE. So if
you leave m_bAutoDelete as TRUE, the handle WILL be closed when the thread finishes.
joe
Post by David Lowndes
Post by Newsgroupie
But when the thread finishes prematurely the handle is no longer valid
Why isn't it valid? The thread handle should be valid until you
explicitly call CloseHandle on it. The fact that the thread has
finished should not be invalidating the thread handle.
Post by Newsgroupie
I always have the thread set to auto delete.
What do you mean by that?
Dave
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer
2008-01-22 22:54:10 UTC
Permalink
I would suggest forgetting that WFSO exists in this context. Do a PostMessage to notify
your main GUI thread that your worker thread has stopped. That way, the legality of the
handle is irrelevant.

/* static */ UINT CMyClass::mythread(LPVOID p)
{
CMyClass * me = (CMyClass *)p;
me->ThreadBody();
me->PostMessage(UWM_THREAD_FINISHED);
return 0;
}

There is no such concept as a thread "finishing prematurely". A thread finishes when it
wants to finish, and whether that is based on an Event object, boolean, or running out of
stuff to do is pretty much irrelevant.

Don't use CEvent or any MFC synchronization primitive; they are all crap (to put it
mildly)

See my essays on threading on my MVP Tips site.
joe
Post by Newsgroupie
Hello,
I create a worker thread(s) which will usually run until I tell it to
stop, which I do by signalling a CEvent object which the thread will
see and drop out of the thread function.
However, sometimes the thread my drop out early because it has
completed its tasks or an error has occurred.
When I create this thread I retain a copy of its handle so that after
I have set the stop event I can pass the handle to
WaitForMultipleObject (along with several other thread handles) and
wait for the thread to complete (as it may spend some time tidying a
few things up between it being told to stop and it actually
finishing).
But when the thread finishes prematurely the handle is no longer valid
and so WaitForMultipleObject fails with a GetLastError of 6 (invalid
handle).
I always have the thread set to auto delete. The stop CEvent is not
deleted with the thread.
Can someone please suggest a better way for me to do this sort of
thing so that I can cleanly and safely detect that a running thread
has stopped and that previously running threads have also stopped.
I suppose what I really need to find out is if a thread handle is
still valid?
Many thanks in advance,
'Newsgroupie'
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Continue reading on narkive:
Loading...