Board index » Visual Studio » Thread Deadlock

Thread Deadlock

Visual Studio265
Hi All,



I have a dialog based main app that spins off a thread that is running for

the lifetime of the app. The thread is doing some trivial stuff but when

clicking a button it starts a long lasting task. The event handler for

pressing the button also pops up a modal dialog box so the user can abort

the task being performed by the thread. The thread executing the task

accesses functions in the main app to update the GUI and retrieves some

data. When the task if finished the thread goes back into the normal state

and the dialog box disapears. All this works without any problem.



The problem occurs when quiting the app. In OnDestroy I set a flag for the

thread to exit. Then I call GetExitCodeThread in a loop to wait for the

thread to die. At this point the app sometimes locks up. It never locks up

when I remove the code in the thread that updates the GUI of the main app.

My conclusion is that the thread for the main app is locked in OnDestroy. If

at that time the thread tries to call some function in the main app it waits

until OnDestroy is done but OnDestroy waits for the thread to die ->

deadlock. But if this is true then why is there no deadlock when the thread

is doing the long task described above? At this time the main app is stuck

in the event handler for the pressed button (because it is showing the modal

dialog box). Applying the same logic the thread can't access functions in

the main app because the main app is stuck in the even handler.



What is the solution to this problem? On idea is to send messages back and

forth instead of the thread calling functions directly. Because there are a

lot of functions being called this would be very cumbersom, though. Another

solution would be to do something with critical sections. Finally, when the

user choses to exit I could spin off another thread that waits for all other

threads to die and only then this thread send the actual message to

terminate the app.



Any inputs/comments are appreciated.



Rob


-
 

Re:Thread Deadlock

Quote
The problem occurs when quiting the app. In OnDestroy I set a flag for =

the

thread to exit. Then I call GetExitCodeThread in a loop to wait for =

the

thread to die. At this point the app sometimes locks up. It never =

locks up

when I remove the code in the thread that updates the GUI of the main =

app.

My conclusion is that the thread for the main app is locked in =

OnDestroy. If

at that time the thread tries to call some function in the main app it =

waits

until OnDestroy is done but OnDestroy waits for the thread to die ->

deadlock. But if this is true then why is there no deadlock when the =

thread

is doing the long task described above? At this time the main app is =

stuck

in the event handler for the pressed button (because it is showing the =

modal

dialog box). Applying the same logic the thread can't access functions =

in

the main app because the main app is stuck in the even handler.





If your worker thread uses the main thread to update the GUI, the main =

thread must be prepared to process messages. If your OnDestroy is simply =

looping on GetExitCodeThread, no messages will be processed. You have to =

get and dispatch those messages yourself. On the other hand, when your =

main thread is waiting for a modal dialog to close, the thread is not =

stuck in the event handler. Modal dialogs implement their own message =

loop, that keep the system responding.



To solve your problem, you can call PeekMessage and DispatchMessage =

while you are waiting for the thread to terminate.



HTH

Heinz

-

Re:Thread Deadlock



"Heinz Ozwirk" <wansor42@gmx.de>wrote in message

Quote
>The problem occurs when quiting the app. In OnDestroy I set a flag for

the

>thread to exit. Then I call GetExitCodeThread in a loop to wait for the

>thread to die. At this point the app sometimes locks up. It never locks

up

>when I remove the code in the thread that updates the GUI of the main

app.

>My conclusion is that the thread for the main app is locked in OnDestroy.

If

>at that time the thread tries to call some function in the main app it

waits

>until OnDestroy is done but OnDestroy waits for the thread to die ->

>deadlock. But if this is true then why is there no deadlock when the

thread

>is doing the long task described above? At this time the main app is

stuck

>in the event handler for the pressed button (because it is showing the

modal

>dialog box). Applying the same logic the thread can't access functions in

>the main app because the main app is stuck in the even handler.





Quote
If your worker thread uses the main thread to update the GUI, the main

thread must be prepared to process messages. If your>OnDestroy is simply

looping on GetExitCodeThread, no messages will be processed. You have to get

and dispatch those>messages yourself. On the other hand, when your main

thread is waiting for a modal dialog to close, the thread is not stuck in

Quote
the event handler. Modal dialogs implement their own message loop, that

keep the system responding.



Quote
To solve your problem, you can call PeekMessage and DispatchMessage while

you are waiting for the thread to terminate.



Heinz & all,



Thanks for your input. I have a question, though. How can an app update

itself when an event handler of this app creates a modal dialog? The app

does not get out of the event handler until the dialog is closed. So how

does the message loop in the modal dialog help the app to be updated? In my

thread I can't directly call a function in the main app (I am not sending

messages but do a direct call). So how can a function in the main app be

executed when the app is stuck in the event handler that popped up the modal

dialog?



Regards,

Robert





-

Re:Thread Deadlock

rob wrote:

Quote
Thanks for your input. I have a question, though. How can an app update

itself when an event handler of this app creates a modal dialog? The app

does not get out of the event handler until the dialog is closed. So how

does the message loop in the modal dialog help the app to be updated? In my

thread I can't directly call a function in the main app (I am not sending

messages but do a direct call). So how can a function in the main app be

executed when the app is stuck in the event handler that popped up the modal

dialog?



1. Message handling



Every window has a function that gets called when a message needs to be

dispatched to it. This function is registered to a window, and this is

hidden from you in MFC, but create non-MFC project and see what wizard

gave you. This function is called from a Message Pump. All message pumps

(including those in both MFC and non-MFC projects, dialog boxes, even in

message boxes (created with [Afx]MessageBox) look pretty much like this:



while( (bRet = GetMessage( &msg, NULL, 0, 0 ))>0)

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}



So, message handler for one window (dialog) gets called from message

handler of another window (main window). While in dialog, message pump

can call main window's message handler just as well. Only thing to

remember is that message pump must always be "alive", which means that

you can't wait too long in one message handler and not do something that

creates another message pump.



2. Call Stack of a Thread



When debugging observe the Call Stack. You'll see a number of functions

one on top of another. It doesn't matter what are those functions, or

whose classes are they belonging to. What matters is that every thread

has its own call stack, totally independent of stacks of other threads.

To put it another way: threads have context, classes don't have context.

It doesn't matter if that class is derived from CWinApp, or whatever.



HTH



-

Re:Thread Deadlock

rob wrote:

Quote
Heinz & all,



Thanks for your input. I have a question, though. How can an app update

itself when an event handler of this app creates a modal dialog? The app

does not get out of the event handler until the dialog is closed. So how

does the message loop in the modal dialog help the app to be updated? In my

thread I can't directly call a function in the main app (I am not sending

messages but do a direct call). So how can a function in the main app be

executed when the app is stuck in the event handler that popped up the modal

dialog?



Regards,

Robert



The modal dialog



The modal dialog does not interfere with custom message processing by

the application's other windows. Direct calls that update windows

created in the main thread are not supported by MFC and can lead to

several problems. Your thread should PostMessage to request the main

thread to update things, and PostMessage to signal when it has finished.

See www.mvps.org/vcfaq/mfc/index.htm">www.mvps.org/vcfaq/mfc/index.htm



--

Scott McPhillips [VC++ MVP]



-

Re:Thread Deadlock

"rob" <rmdiv2001@hotmail.com>wrote in message news:<aIw1d.742$Y65.345@newsread1.news.pas.earthlink.net>...

Quote
"Heinz Ozwirk" <wansor42@gmx.de>wrote in message

news:ci6369$ijn$07$1@news.t-online.com...

>>The problem occurs when quiting the app. In OnDestroy I set a flag for

the

>>thread to exit. Then I call GetExitCodeThread in a loop to wait for the

>>thread to die. At this point the app sometimes locks up. It never locks

up

>>when I remove the code in the thread that updates the GUI of the main

app.

>>My conclusion is that the thread for the main app is locked in OnDestroy.

If

>>at that time the thread tries to call some function in the main app it

waits

>>until OnDestroy is done but OnDestroy waits for the thread to die ->

>>deadlock. But if this is true then why is there no deadlock when the

thread

>>is doing the long task described above? At this time the main app is

stuck

>>in the event handler for the pressed button (because it is showing the

modal

>>dialog box). Applying the same logic the thread can't access functions in

>>the main app because the main app is stuck in the even handler.





>If your worker thread uses the main thread to update the GUI, the main

thread must be prepared to process messages. If your>OnDestroy is simply

looping on GetExitCodeThread, no messages will be processed. You have to get

and dispatch those>messages yourself. On the other hand, when your main

thread is waiting for a modal dialog to close, the thread is not stuck in

>the event handler. Modal dialogs implement their own message loop, that

keep the system responding.



>To solve your problem, you can call PeekMessage and DispatchMessage while

you are waiting for the thread to terminate.



Heinz & all,



Thanks for your input. I have a question, though. How can an app update

itself when an event handler of this app creates a modal dialog? The app

does not get out of the event handler until the dialog is closed. So how

does the message loop in the modal dialog help the app to be updated? In my

thread I can't directly call a function in the main app (I am not sending

messages but do a direct call). So how can a function in the main app be

executed when the app is stuck in the event handler that popped up the modal

dialog?



Regards,

Robert



Hi there Robert,

A classic problem , that is why you should use modalless dialogs that

doesn't hold the main thread message loop blocked so it can process

incoming messages.

Or you could set up a timer or override DoModal() to do a

PeekMessage() and CWinApp::PumpMessage() that will let the applicaion

a chance to process some messages once in a while.



Hope it helped,

Omry Levy

-

Re:Thread Deadlock

rob wrote:



Quote
Hi All,



I have a dialog based main app that spins off a thread that is running for

the lifetime of the app. The thread is doing some trivial stuff but when

clicking a button it starts a long lasting task. The event handler for

pressing the button also pops up a modal dialog box so the user can abort

the task being performed by the thread. The thread executing the task

accesses functions in the main app to update the GUI and retrieves some

data. When the task if finished the thread goes back into the normal state

and the dialog box disapears. All this works without any problem.



The problem occurs when quiting the app. In OnDestroy I set a flag for the

thread to exit. Then I call GetExitCodeThread in a loop to wait for the

thread to die.



All things being equal, you should be using WaitForSingleObject on the

thread handle. That method waits using zero CPU time, while your loop

consumes all available cycles. See this message for instructions on safely

waiting for MFC threads to exit:



http://groups.google.com/groups?selm" rel="nofollow" target="_blank">groups.google.com/groups=m3ep501falcm3ecgdb1tsof6p42f32fvk7%404ax.com



Quote
At this point the app sometimes locks up. It never locks up

when I remove the code in the thread that updates the GUI of the main app.



"Updating the GUI" implies SendMessage, and you're talking about

inter-thread SendMessage, which is indeed prone to deadlock unless you

design to avoid it. See these messages for more on this subject and

alternative approaches:



http://groups.google.com/groups?selm" rel="nofollow" target="_blank">groups.google.com/groups=6v28f0d5aadcafkfp2682ecjva7qltssif%404ax.com

http://groups.google.com/groups?selm" rel="nofollow" target="_blank">groups.google.com/groups=gli6k0p8t7elm3sb6pid88rqbl03f8o4m6%404ax.com



In a nutshell, you'll probably want to define a custom message and

PostMessage it to the dialog window, which is described in the

mvps.org/vcfaq link.



Quote
My conclusion is that the thread for the main app is locked in OnDestroy.



Correct! Your main thread is blocked in OnDestroy, not processing the

messages the secondary thread is trying to send it. This would also happen

with WaitForSingleObject, but keep reading.



Quote
If at that time the thread tries to call some function in the main app it waits

until OnDestroy is done but OnDestroy waits for the thread to die ->

deadlock. But if this is true then why is there no deadlock when the thread

is doing the long task described above? At this time the main app is stuck

in the event handler for the pressed button (because it is showing the modal

dialog box). Applying the same logic the thread can't access functions in

the main app because the main app is stuck in the even handler.



Modal dialogs boxes run their own message loops, and as explained in the

messages linked to above, they call functions that allow inter-thread

SendMessage calls to go through. Note that SendMessage is a very special

function; ordinary functions of course don't block or context switch to the

target thread as SendMessage does. Instead, the calling thread executes

ordinary functions concurrently with other threads.



Quote
What is the solution to this problem? On idea is to send messages back and

forth instead of the thread calling functions directly. Because there are a

lot of functions being called this would be very cumbersom, though.



But SendMessage is your problem, not your solution. :) Practically every

CWnd function amounts to one or more SendMessage calls under the hood, and

this is also true for many Windows API functions, such as SetWindowText. As

mentioned earlier, custom messages and PostMessage represent your probable

solution.



Quote
Another solution would be to do something with critical sections.



Not sure how that would help, though if you're accessing data in multiple

threads and modifying it at all, you do need to synchronize this access.



Quote
Finally, when the

user choses to exit I could spin off another thread that waits for all other

threads to die and only then this thread send the actual message to

terminate the app.



You're right to want to join with all secondary threads before allowing the

primary thread to exit. If you don't, they'll continue to run while the

environment in which they live is being destroyed all around them, including

things like static duration objects, MFC, the CRT, and so forth, which can

have all sorts of nasty side effects. A secondary manager thread might work,

but you'd have to return to your message loop in order for the SendMessage

calls to work. This leaves your app in a weird state in which it's logically

dead but still needs to process messages from the secondary thread, and

dropping back into the MFC message loop is probably not the best way to deal

with this, as it can leave you open to subsequent user input messages. I've

dealt with a similar situation by not using a manager thread, but instead

using MsgWaitForMultipleObjects in a loop that discards input messages, so

that user input is ruled out while I wait for my handles to become signaled.

This method works well when the waiting period is brief. It avoids changes

in window appearance that may occur when you disable a window. It keeps

things local, avoiding any possibility that MFC will shut down the app on

its own, as it does when the main window is closed, or otherwise interfere

with your plan.



As the MsgWaitForMultipleObjects function is tricky to use, see this message

for a template you can modify to suit your needs:



http://groups.google.com/groups?selm" rel="nofollow" target="_blank">groups.google.com/groups=gq79f0tf209iivgo5ovucqtbm4tf72v90u%404ax.com



You would need to replace the following:



if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))

theApp.PumpMessage();



with a version that discards input messages. However, the obvious approach

of examining the message before calling PumpMessage doesn't work. Do you see

why? The comment in the function below explains it (note that WM_PAINT is a

low priority message):



// For WM_KICKIDLE

#include <afxpriv.h>



bool

PumpMessageDiscardingInputMessages(HWND hWnd)

{

// It's possible for PeekMessage to return WM_PAINT but for a subsequent

// GetMessage to return WM_KEYDOWN. Thus, we can't call PumpMessage

// directly, as it does its own GetMessage.



MSG msg;

if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))

{

if (msg.message != WM_KICKIDLE)

{

if (IsInputMessage(msg)

&& (!hWnd

|| msg.hwnd == hWnd

|| (msg.hwnd && IsChild(hWnd, msg.hwnd))))

return true;

if (!AfxGetApp()->PreTranslateMessage(&msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

return true;

}

return false;

}



Finally, here's my IsInputMessage:



#include <algorithm>



inline bool

FindMsg(const UINT msg, const UINT* pTab, const UINT* pTabEnd)

{

return std::find(pTab, pTabEnd, msg) != pTabEnd;

}



bool

IsInputMessage(

const UINT msg,

const bool keys /*= true*/,

const bool mice /*= true*/,

const bool commands /*= true*/)

{

static const UINT keyMsgTab[] =

{

WM_KEYDOWN,

WM_KEYUP,

WM_SYSKEYDOWN,

WM_SYSKEYUP,

WM_CONTEXTMENU

};



static const UINT miceMsgTab[] =

{

WM_LBUTTONDOWN, WM_LBUTTONUP,

WM_LBUTTONDBLCLK,

WM_MBUTTONDOWN, WM_MBUTTONUP,

WM_MBUTTONDBLCLK,

WM_RBUTTONDOWN, WM_RBUTTONUP,

WM_RBUTTONDBLCLK,

WM_XBUTTONDOWN, WM_XBUTTONUP,

WM_XBUTTONDBLCLK,

WM_NCLBUTTONDOWN, WM_NCLBUTTONUP,

WM_NCLBUTTONDBLCLK,

WM_NCMBUTTONDOWN, WM_NCMBUTTONUP,

WM_NCMBUTTONDBLCLK,

WM_NCRBUTTONDOWN, WM_NCRBUTTONUP,

WM_NCRBUTTONDBLCLK,

WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,

WM_NCXBUTTONDBLCLK,

};



static const UINT commandMsgTab[] =

{

WM_COMMAND,

WM_SYSCOMMAND,

WM_CONTEXTMENU

};



// NB: WM_CONTEXTMENU is generated as a result of pressing the Menu key,

// so eat it if we're discarding keys or commands.



// VCFIXUP - FindMsg could be a template function but VC6 doesn't like

// UINT (&x)[size]

#define FIND(tab) FindMsg(msg, tab, tab+sizeof(tab)/sizeof(tab[0]))



return (keys && FIND(keyMsgTab))

|| (commands && FIND(commandMsgTab))

|| (mice && FIND(miceMsgTab));



#undef FIND

}





--

Doug Harrison

Microsoft MVP - Visual C++

-