15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Thread Deadlocking, recomendations needed?

prmslick -- prmslick@infi.net
Thursday, February 22, 1996

VC++4, MFC:

Thanks to all of the helpful responses I now know (or strongly suspect) why I 
could not successfully halt a worker thread.  I got several good sugestions 
about how to halt the thread.  I beleive any of them will work.  One of you 
folks mentioned a possible deadlock.  A painful review of my code showed just 
that.  But I'm a little green here and don't know exactly what is the best way 
to get around the deadlock.

Heres an overview of the app.

SDI application.  
Two threads, a primary and a worker.

Primary thread controls an I/O status window, and a dialog box.  Both of which 
recieve i/o messages from the worker thread.

Worker thread, loops until a TimeToExit flag is set. (Could also be an event as 
I've been advised).  The flag is checked at the top and bottom of the loop.  In 
the middle of the loop, I/O activity is directed to the dialog box and status 
window (of the primary thread) via Cwnd->SendMessage(...) calls.  

Strategy to End thread from Primary Thread.
	Set TimeToExit flag to TRUE;
	WaitForSingleObject(WorkerThreadHandle)

Deadlock:
	In the middle of the worker thread, I/O was recieved from the com port. The 
worker thread advised the status window and dialog box of the activity with Cwnd->SendMessage(...)
calls.  The Primary Thread is blocked waiting for the worker thread to end and 
won't process the messages.  The SendMessage() call waits until the message was 
processed before continuing.  Thus a deadlock.

I've tried (at a previous time) to use PostMessage() but the performance 
dropped significantly.

I imagine programmers with multithread experience have encountered this and 
similar problems in the past.  Although I have several books that cover threads 
in general, none of the really discuss deadlock scenerios and how to avoid 
them.  Richter/Locke's book Windows95 a developers guide dosn't really address 
much MFC, and my review of the text indicates he's working more in a "hook" 
like environment.  I'm afraid if there is an answer in his book, its went over 
my head.

Any and all comments would be greatly appreaciated.  The last volley of 
responses have taught me a lot.  Hopefully I'll be able to contribute here in 
time.




prmslick@infi.net
Using Pegasus Mail Win95 and OS2 Warp



David W. Gillett -- DGILLETT@expertedge.com
Friday, February 23, 1996

[Mini-digest: 2 responses]

> Strategy to End thread from Primary Thread.
> 	Set TimeToExit flag to TRUE;
> 	WaitForSingleObject(WorkerThreadHandle)
> 
> Deadlock:
> 	In the middle of the worker thread, I/O was recieved from the com port. The 
> worker thread advised the status window and dialog box of the activity with Cwnd->SendMessage(...)
> calls.  The Primary Thread is blocked waiting for the worker thread to end and 
> won't process the messages.  The SendMessage() call waits until the message was 
> processed before continuing.  Thus a deadlock.

  If the worker thread can be sending messages to the UI thread after
TimeToExit is set, then (obviously?) the UI thread should stll be in
its message loop.  This suggests that the UI thread should not begin
its WaitForSingleObject until it gets a message (posted, not sent)
that the worker thread has seen and acknowledges the flag. 

  [Checking at both the top and the bottom of the loop is redundant --
the fact that it's a loop puts these two checks right next to each
other.] 

> I've tried (at a previous time) to use PostMessage() but the
> performance dropped significantly.

  Actually, overall performance with PostMessage() should be better 
than with SendMessage(), because time-consuming thread-switches are 
reduced.  Timeliness, however, can suffer, and this can negatively 
impact the user's *perception* of the program's performance.
  One idea you might try is to bump the priority of the UI thread by 
a notch while mostly using PostMessage.
 
> I imagine programmers with multithread experience have encountered
> this and similar problems in the past.  Although I have several
> books that cover threads in general, none of the really discuss
> deadlock scenerios and how to avoid them.  Richter/Locke's book
> Windows95 a developers guide dosn't really address much MFC, and
> my review of the text indicates he's working more in a "hook" like
> environment.  I'm afraid if there is an answer in his book, its
> went over my head.

  I suspect that the coverage of threads and synchronization in that 
book may be a little skimpy, because Richter covers them in great 
detail in "Advanced Windows".

Dave

 
-----From: "Mark F. Fling" 

Thanks for you're more complete description of the primary and work 
threads.  You're problem arises when you block the primary thread and 
shut down the message pump of the application. I'm assuming by your 
description you've got a dialog box up along with some form of status 
indication, such as a progress bar or page counter, or the like.

I'm assuming you create your worker I/O thread in response to some
menu command or during OnInitInstance.  If so, simply issue the
CreateThead/afxBeginThread call and continue on.  There's no need to
block anything in the main (user interface) thread.  Thus, the
message loop of the application still runs and accepts/processes
window update messages.

The I/O worker thread should then be able to post update messages to 
the main window using SendNotifyMessge, which returns immediately if 
the posting thread did not create the window.  You might also need to 
call UpdateWindow from the background thread to ensure a repaint 
of the main window.

Your user interface contains a modal dialog box? Why?  The whole idea 
of worker threads is to improve the responsiveness of the user 
interface thread and eliminate a "mode". Otherwise, you'd move your 
I/O loop into your app and use traditional OnIdle processing to keep 
the app semi-responsive.  I gather your status thingy is on the main 
window informing the user of the background I/O status.  If the user 
wants to stop the I/O, give em a menu item.  I suggest you ditch the 
dialog box.

This isn't a deadlock issue - it's really a design issue.  Deadlocks 
are simply manifestations of too-complex multithreaded designs, IMHO.





Pierre De Boeck -- pde@miscrit.be
Monday, February 26, 1996

prmslick wrote:
> Heres an overview of the app.
> 
> SDI application.
> Two threads, a primary and a worker.

Why not create a third thread dedicated to the status window and 
activity. You will have
	- a primary thread that handles initialisation, 	  
	  termination, creation of the two sub threads and 	  
	  waiting for the dead of these two threads 	  	  
	  (WaitForMultipleObject)
	- the worker thread that sends messages to the staus 
	  thread. Among these messages is a special one to 
	  signal that the status thread must die.
	- the status thread that processes the messages and 
	  terminates whenn it receives the special "exit" 
	  message.

So the termination process will look like this:
	- the primary thread set the TimeToExit flag to TRUE
	  and waits for the dead of the two threads.
	- the worker thread detects that the flag is TRUE, sends 
	  the "exit" message to the status thread with the 
	  Cwnd->SendMessage(...) call, and exit.
	- the status thread receives the "exit" message and 
	  exit.
	- the primary thread is signaled and terminates.

[Moderator's question: Could you explain the advantage to this
approach over the 2-thread approach?  It seems heavy-handed to
me, given that the primary thread just sits there when it
could be displaying status during its idle time.]

-- 
Pierre De Boeck
Mission Critical, Wijnegemhofstraat 199, B-3071 Erps-Kwerps 
(Belgium)
Phone: +32 2 759 95 60  Fax: +32 2 759 27 60
email: pde@miscrit.be

                                      ///               
                                     (. .)           
---------------------------------oOO--(_)--OOo------------------
----



Pierre De Boeck -- pde@miscrit.be
Wednesday, February 28, 1996

Pierre De Boeck wrote:
> 
> prmslick wrote:
> > Heres an overview of the app.
> >
> > SDI application.
> > Two threads, a primary and a worker.
> 
> Why not create a third thread dedicated to the status window and
> activity. You will have
>         - a primary thread that handles initialisation,
>           termination, creation of the two sub threads and
>           waiting for the dead of these two threads
>           (WaitForMultipleObject)
>         - the worker thread that sends messages to the staus
>           thread. Among these messages is a special one to
>           signal that the status thread must die.
>         - the status thread that processes the messages and
>           terminates whenn it receives the special "exit"
>           message.
> 
> So the termination process will look like this:
>         - the primary thread set the TimeToExit flag to TRUE
>           and waits for the dead of the two threads.
>         - the worker thread detects that the flag is TRUE, sends
>           the "exit" message to the status thread with the
>           Cwnd->SendMessage(...) call, and exit.
>         - the status thread receives the "exit" message and
>           exit.
>         - the primary thread is signaled and terminates.
> 
> [Moderator's question: Could you explain the advantage to this
> approach over the 2-thread approach?  It seems heavy-handed to
> me, given that the primary thread just sits there when it
> could be displaying status during its idle time.]
> 

You are totally right! The primary thread can acts as the 
"status" thread but its WaitForSingleObject(hWorkerThread,..) 
call must be done AFTER the receiption of the special "exit" 
message stemming from the worker thread. This ensures a 
safe-deadlock situation since 
	- the series of messages m0,m1,...exit are guaranteed to 
	  be catched by the status thread (since it is not yet 
	  in its waiting event call)
	- the WaitForSingleObject() is guaranteed to terminate 	  
	  since at this point, the worker thread have sent its 
	  "exit" message and thus it is dead or is dying.

-- 
Pierre De Boeck
Mission Critical, Wijnegemhofstraat 199, B-3071 Erps-Kwerps 
(Belgium)
Phone: +32 2 759 95 60  Fax: +32 2 759 27 60
email: pde@miscrit.be

                                      ///               
                                     (. .)           
---------------------------------oOO--(_)--OOo------------------
----



John Addis -- jaddis@erols.com
Thursday, February 29, 1996

prmslick wrote:
> Strategy to End thread from Primary Thread.
>         Set TimeToExit flag to TRUE;
>         WaitForSingleObject(WorkerThreadHandle)
> 
> Deadlock:
>         In the middle of the worker thread, I/O was recieved from the com port. The
> worker thread advised the status window and dialog box of the activity with Cwnd->SendMessage(...)
> calls.  The Primary Thread is blocked waiting for the worker thread to end and
> won't process the messages.  The SendMessage() call waits until the message was
> processed before continuing.  Thus a deadlock.
> 
> 
> prmslick@infi.net
> Using Pegasus Mail Win95 and OS2 Warp


How about checking the TimeToExit flag immediately before calling 
SendMessage()?

-- 
John Addis        Master of Time and Space
jaddis@erols.com  C++, MFC, Win32, Win95, TCP/IP
"Invalid or missing REALITY.COM Universe halted."





Marty Fried -- mfried@linex.com
Sunday, March 03, 1996

At 11:39 PM 2/29/96 -0500, John Addis wrote:
>prmslick wrote:
>> Strategy to End thread from Primary Thread.
>>         Set TimeToExit flag to TRUE;
>>         WaitForSingleObject(WorkerThreadHandle)
>> . . .

>How about checking the TimeToExit flag immediately before calling 
>SendMessage()?

Wouldn't that just reduce the chances, rather than eliminate the
problem?  What if the worker thread gets prempted between checking
the flag and sending the message?

One possibility that comes to mind is this:  after setting the TimeToExit
flag in the Primary thread, perhaps do a WaitForSingleObject with a fairly
short timeout, and if the return value is WAIT_TIMEOUT, process pending
messages, then loop back to WaitForSingleObject again, until you don't
timeout.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 Marty Fried (mfried@linex.com)
 Marin County, California






| Вернуться в корень Архива |