Multi threaded Application with 2 threads
1 -main thread uses COM objects and implements them and also start another
thread that process something
thread is created using _beginthread function.
Thread finishes in natural way.
I make WaitForSingleObject that waits for thread to finish in main thread
But this function waits forever
Any help and advice would be appreciated
Best Regards
Igor Dumanskyy
_beginthread is dangerous and should be avoided, because it may return
a stall HANDLE if the created thread exits quickly (see documentation
page on _beginthread in MSDN). Use _beginthreadex instead (and do not
forget to call CloseHandle on the thread handle once done).
If this isn't your problem, we will need to see some actual code to
help you...
Arnaud
MVP - VC
!handle VALUE f
will also display useful iformation about the handle you are waiting for.
VALUE is the hex value of the handle you used for the WaitForSingleObject
call.
Dan
--
This posting is provided "AS IS" with no warranties, and confers no rights.
<adeb...@club-internet.fr> wrote in message
news:1172761638.9...@v33g2000cwv.googlegroups.com...
The OP's problem does not seem to be related to the thread handle -although
the above statement applies almost to any API that takes thread handle as a
parameter, WaitXXX functions are exception to this rule....
As long as thread has not entered terminated state, any wait on its handle
blocks, because its ETHREAD is in unsignaled state. When thread enters
terminated state, its ETHREAD becomes signalled, so that any wait its handle
gets satisfied, no matter if thread's exit was gracefull or not. Therefore,
if you pass this "stall" handle to WaitForSingleObject(), your wait will just
get immediately satisfied, and, according to the OP, this is not what happens
here....
Probably, the OP waits not on thread handle but on that to some other
dispatcher object that the target thread is supposed to set to the signalled
state (at least the OP did not explicitly say that he waits on the thread
handle). If this is the case, there is a good chance that his code just
somehow "forgets" to set to the signalled state. In any case, it is hard to
say anything without actually seeing the code....
Anton Bassov
Bellow I have added a code of class that wraps thread routines.
I am using it
Start and Wait for finish
Going (debugging) step by step it finishes normally but WaitForSingleObject
waits forever
Any help will be appreciated
Thanks in advance
Best regards
Agentd : )
//----------------------code---------------------------------//
class IThread
{
protected:
virtual void Execute()=0;
public:
virtual bool Start()=0;
virtual bool WaitForFinish()=0;
virtual bool Initialize()=0;
virtual bool Finalize()=0;
virtual void join()=0;
virtual bool IncreasePriority()=0;
virtual bool DecreasePriority()=0;
virtual bool GetPriority(intmsd_t& o_Priority)const=0;
virtual bool GetHighestPriority(intmsd_t& o_Priority)const=0;
virtual bool GetLowestPriority(intmsd_t& o_Priority)const=0;
virtual ~IThread()throw()=0;
};
//---------------------------------------------------------------------------------------------
inline IThread::~IThread()throw()
{
}
#include "windows.h"
#include "process.h"
inline uintmsd_t GetCurrentThreadID()
{
return static_cast<uintmsd_t>(GetCurrentThreadId());
}
class Thread : public IThread
{
HANDLE m_ThreadHandle;
static uintmsd_t THREAD_FUNCTION _ThreadExecute(void* Ptr);
protected:
Thread();
public:
virtual bool Start();
virtual bool WaitForFinish();
virtual bool Stop();
virtual bool Initialize()=0;
virtual bool Finalize()=0;
virtual bool IncreasePriority();
virtual bool DecreasePriority();
virtual bool GetPriority(intmsd_t& o_Priority)const;
virtual bool GetHighestPriority(intmsd_t& o_Priority)const;
virtual bool GetLowestPriority(intmsd_t& o_Priority)const;
virtual ~Thread()throw();
};
//-------------------------------------------------------------------------------------------------------------
class IThread
{
protected:
virtual void Execute()=0;
public:
virtual bool Start()=0;
virtual bool WaitForFinish()=0;
virtual bool Initialize()=0;
virtual bool Finalize()=0;
virtual void join()=0;
virtual bool IncreasePriority()=0;
virtual bool DecreasePriority()=0;
virtual bool GetPriority(intmsd_t& o_Priority)const=0;
virtual bool GetHighestPriority(intmsd_t& o_Priority)const=0;
virtual bool GetLowestPriority(intmsd_t& o_Priority)const=0;
virtual ~IThread()throw()=0;
};
//---------------------------------------------------------------------------------------------
inline IThread::~IThread()throw()
{
}
#include "windows.h"
#include "process.h"
inline uintmsd_t GetCurrentThreadID()
{
return static_cast<uintmsd_t>(GetCurrentThreadId());
}
class Thread : public IThread
{
HANDLE m_ThreadHandle;
static uintmsd_t THREAD_FUNCTION _ThreadExecute(void* Ptr);
protected:
Thread();
public:
virtual bool Start();
virtual bool WaitForFinish();
virtual bool Stop();
virtual bool Initialize()=0;
virtual bool Finalize()=0;
virtual bool IncreasePriority();
virtual bool DecreasePriority();
virtual bool GetPriority(intmsd_t& o_Priority)const;
virtual bool GetHighestPriority(intmsd_t& o_Priority)const;
virtual bool GetLowestPriority(intmsd_t& o_Priority)const;
virtual ~Thread()throw();
};
//-------------------------------------------------------------------------------------------------------------
inline uintmsd_t Thread::_ThreadExecute(void* Ptr)
{
if(NULL==Ptr)
{
assert(NULL==Ptr);
return 1L;
}
reinterpret_cast<Thread*>(Ptr)->Execute();
return 0L;
}
inline Thread::Thread()
:m_ThreadHandle(NULL)
{
}
inline bool Thread::Start()
{
if(NULL==m_ThreadHandle)
{
m_ThreadHandle=reinterpret_cast<HANDLE>(_beginthreadex(NULL,0,Thread::_ThreadExecute,this,0,NULL));
BOOL r =
::SetThreadPriority((HANDLE)m_ThreadHandle,THREAD_PRIORITY_LOWEST);
return true;
}
return false;
}
inline bool Thread::WaitForFinish()
{
if(NULL!=m_ThreadHandle)
{
DWORD retVal=::WaitForSingleObject((this->m_ThreadHandle),INFINITE);
if(WAIT_OBJECT_0==retVal)
{
return true;
}
else if(WAIT_TIMEOUT==retVal)
{
return false;
}
else
{
return false;
}
}
return true;
}
inline bool Thread::Stop()
{
if(NULL!=m_ThreadHandle)
{
if(0<TerminateThread(m_ThreadHandle,0))
{
CloseHandle(m_ThreadHandle);
m_ThreadHandle=NULL;
return true;
}
return false;
}
return true;
}
inline bool Thread::IncreasePriority()
{
if(NULL==this->m_ThreadHandle)
{
return false;
}
intmsd_t lCurrentPriority;
if(!this->GetPriority(lCurrentPriority))
{
return false;
}
switch(lCurrentPriority)
{
case THREAD_PRIORITY_TIME_CRITICAL: //15 Base-priority level of 15
{
return false;
}
case THREAD_PRIORITY_HIGHEST: //2 Priority 2 points above the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_TIME_CRITICAL;
break;
}
case THREAD_PRIORITY_ABOVE_NORMAL: //1 Priority 1 point above the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_HIGHEST;
break;
}
case THREAD_PRIORITY_NORMAL: //0 Normal priority for the priority class.
{
lCurrentPriority=THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case THREAD_PRIORITY_BELOW_NORMAL://-1 Priority 1 point below the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_NORMAL;
break;
}
case THREAD_PRIORITY_LOWEST: //-2 Priority 2 points below the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case THREAD_PRIORITY_IDLE: //-15 Base priority of 1
{
lCurrentPriority=THREAD_PRIORITY_LOWEST;
break;
}
default:
return false;
}
return (0<::SetThreadPriority(this->m_ThreadHandle,lCurrentPriority)) ;
}
inline bool Thread::DecreasePriority()
{
if(NULL==this->m_ThreadHandle)
{
return false;
}
intmsd_t lCurrentPriority;
if(!this->GetPriority(lCurrentPriority))
{
return false;
}
switch(lCurrentPriority)
{
case THREAD_PRIORITY_TIME_CRITICAL: //15 Base-priority level of 15 for
{
lCurrentPriority=THREAD_PRIORITY_HIGHEST;
break;
}
case THREAD_PRIORITY_HIGHEST: //2 Priority 2 points above the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_ABOVE_NORMAL;
break;
}
case THREAD_PRIORITY_ABOVE_NORMAL: //1 Priority 1 point above the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_NORMAL;
break;
}
case THREAD_PRIORITY_NORMAL: //0 Normal priority for the priority class.
{
lCurrentPriority=THREAD_PRIORITY_BELOW_NORMAL;
break;
}
case THREAD_PRIORITY_BELOW_NORMAL://-1 Priority 1 point below the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_LOWEST;
break;
}
case THREAD_PRIORITY_LOWEST: //-2 Priority 2 points below the priority
class.
{
lCurrentPriority=THREAD_PRIORITY_IDLE;
break;
}
case THREAD_PRIORITY_IDLE: //-15 Base priority of 1
{
return false;
}
default:
return false;
}
return (0<::SetThreadPriority(this->m_ThreadHandle,lCurrentPriority));
}
inline bool Thread::GetPriority(intmsd_t& o_Priority)const
{
if(NULL==this->m_ThreadHandle)
{
return false;
}
o_Priority=::GetThreadPriority(this->m_ThreadHandle);
if(THREAD_PRIORITY_ERROR_RETURN==o_Priority)
{
return false;
}
return true;
}
inline bool Thread::GetHighestPriority(intmsd_t& o_Priority)const{
o_Priority=THREAD_PRIORITY_TIME_CRITICAL;
return true;
}
inline bool Thread::GetLowestPriority(intmsd_t& o_Priority)const
{
o_Priority= THREAD_PRIORITY_IDLE;
return true;
}
inline Thread::~Thread()throw()
{
CloseHandle(this->m_ThreadHandle);
}//----------------------code---------------------------------//
I see it! I see it! Is there a prize?
>inline uintmsd_t Thread::_ThreadExecute(void* Ptr)
>{
> if(NULL==Ptr)
> {
> assert(NULL==Ptr);
> return 1L;
> }
> reinterpret_cast<Thread*>(Ptr)->Execute();
> return 0L;
>}
This is not related to your problem, but are you aware that this "assert"
will never fire? I suspect you wanted to have the "assert" BEFORE the
"if".
>inline bool Thread::Start()
>{
> if(NULL==m_ThreadHandle)
> {
> m_ThreadHandle=reinterpret_cast<HANDLE>(_beginthreadex(NULL,0,Thread::_ThreadExecute,this,0,NULL));
> BOOL r =
>::SetThreadPriority((HANDLE)m_ThreadHandle,THREAD_PRIORITY_LOWEST);
>
> return true;
> }
> return false;
>}
OK, so here we create the thread and tuck the handle away.
>inline bool Thread::WaitForFinish()
>{
> if(NULL!=m_ThreadHandle)
> {
> DWORD retVal=::WaitForSingleObject((this->m_ThreadHandle),INFINITE);
And here is the wait that waits forever.
>inline bool Thread::Stop()
>{
> if(NULL!=m_ThreadHandle)
> {
> if(0<TerminateThread(m_ThreadHandle,0))
> {
> CloseHandle(m_ThreadHandle);
> m_ThreadHandle=NULL;
> return true;
> }
> return false;
> }
> return true;
>}
And here is the reason WHY it waits forever. You terminate the thread, and
then immediately close the handle. As soon as you close the handle, the
handle is invalid, so the WaitForSingleObject is looking at trash memory.
It will never fire.
You should either move the "CloseHandle" and "m_ThreadHandle=NULL" calls to
after the WaitForSingleObject, or put them in the destructor for the class.
When you are doing multithreaded programming, you ALWAYS have to think
about what order things are going to happen.
There is another issue here, however. Using TerminateThread is almost
always a bad idea. It should be considered an "emergency stop", because
the thread does not get a chance to clean itself up properly. A much
better design is to have a flag or an event that you set in the "Stop"
handler, which the thread code will monitor. When the flag or event is
set, the thread exits cleanly, and everybody is happy.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.
I really see the situation concerning terminate I am calling Stop member
function is only for emergency situations
And I completely agree that the better solution is to remove the CloseHandle
functionality in Stop function.
In my case the thread finishes naturally going out of the thread execution
function.
What do you think in this situation.
Best regards
agentd:)
Don't know. When you use _beginthreadex, exiting the thread function
normally will automatically call _endthreadex, which then calls ExitThread.
That should be enough to allow the wait to complete.
What about the Thread object itself? Is it possible you created it on the
stack and it has been destroyed? Your Thread descructor also closes the
handle.
Thanks for your feedback.
In this scenario, it is strange that the WaitForSingleObject did not wake
up with the thread exiting.
I recommend you use windbg to attach/launch your application. After the
thread exits normally while the WaitForSingleObject is still sleeping, you
may break into the debugger with Ctrl+Break and then examine the thread
handle with the command below:
!handle Thread_Handle_Value f
This command will help to dump the details information of the thread handle
and even the thread object. This may help us to reveal why the
WaitForSingleObject is still waiting.
Regarding how to download and configure windbg for debugging, you may refer
to my blog entry below(more specific, the "Using Windbg to obtain
Application Crash information" section):
http://blogs.msdn.com/msdnts/archive/2006/11/24/how-to-debug-application-cra
sh-hang-in-production-environment.aspx
Thanks.
Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
How about this issue now? Have you tried to use windbg to dump the thread
handle information you are waiting on?
If you still need any help or have any concern, please feel free to
feedback, thanks.
I am using COM in this application.
Does it matters?
Is there any thing in COM (ATL) that can cause such kind of problem?
Wait for your early reply
Best Regards
agentd : )
Thanks for your feedback.
Based on my experience, COM/ATL still encapsulates underlying OS Win32
thread programming model, although it introduces several new concepts such
as apartment. I am not a COM/ATL expert, so I do not have much experience
on it. I did not hear any known issue regarding COM/ATL with this strange
behavior.
In current situation, the most informative way to troubleshoot this problem
is checking the status of the thread handle which caused the hang.
Anyway, if you have any problem of using the windbg or need any other help,
please feel free to tell me, thanks.
Have you reviewed my last reply to you? Does it make sense to you? If you
stilll need any help or have any concern, please feel free to tell me,
Thanks for your attempts to help much
I am faced with the following notes in the net
http://www.codeproject.com/threads/SynchronizedThreadNoMfc.asp?df=100&forumid=24862&exp=0&select=880290
Use WaitForSingleObject with caution!
What do you think?
Best Regards
agentd :)
Thanks for your feedback.
I will perform some research on this WaitForSingleObject caution and
provide a reply to you ASAP. Thanks.
Sorry for letting you wait.
Below is my understanding to this caution:
Thread A created windows, so it has message queue/loop internally. So if
threadA calls WaitForSingleObject and other threads(say Thread B) sent
messages to windows belong to threadA, it will cause the threadB hang. This
will only be a problem when threadB uses SendMessage instead of
PostMessage.
MsgWaitForMultipleObjectsEx does not have such problem, because
MsgWaitForMultipleObjectsEx is aware of the message queue. So if any
messages appear in the threadA, MsgWaitForMultipleObjectsEx will wake up
for processing.
I do not think this caution applies to your scenario. This problem will
only hang the thread that is sending message to WaitForSingleObject thread,
it will not hang the WaitForSingleObject calling.
Also, you should not call WaitForSingleObject in a GUI thread, since this
will block the message loop in that thread, which make the user feel like
an application hang.
Hope this helps.
I have further discussed this with other Microsoft Kernel devs. Below is
his comment:
"Messages may be synchronously sent to your window from other processes,
including system components.
For example, whenever the user changes a system parameter (turning on or
off ClearType, changing accessibility settings or UI themes, adjusting
certain mouse settings, changing the desktop wallpaper, etc.) a
WM_SETTINGSCHANGE message is broadcast to all open windows. You're
expected to ignore it, if you don't care about these things; however, if
you simply block and don't process it, the sender could be blocked.
Another example is DDE messages, for older apps that still use those;
they'll deadlock if you don't pump.
This can deadlock yourself as well, because you don’t necessarily know if
an API you’re calling is creating a window. The CoInitialize() mention
hints at that. Most of the Shell APIs require that you create their COM
objects inside a single-threaded apartment; behind the scenes, this is
implemented using a hidden window called “OleMainThreadWndName”, with
calls being marshaled through a message pump and executed by the window’s
wndproc. If you don’t allow that thread to pump messages, any method
being called on objects created by that thread will block.
If you have a window, you need to pump messages to it as fast as possible,
no matter what.(Including the case where an API you call creates a window
without creating a dedicated window pump thread for it.)"
Hope this helps.
At the end you may even replace the event object with critical section
(which is faster than the event).
U
On Mar 1, 10:01 am, agentd <age...@community.nospam> wrote:
> Hello
>
> Multi threaded Application with 2 threads
> 1 -mainthreaduses COM objects and implements them and also start anotherthreadthat process somethingthreadis created using _beginthread function.
In general, it's a bad idea to block while you are in a critical section.
It's so very easy to create a deadlock.