Boost logo

Boost Users :

From: Steve Burnap (steve_at_[hidden])
Date: 2002-02-24 17:03:43


Hi,

I've run into a fairly serious problem attempting to use boost::thread with
the Windows UI.

The problematic part of my application is a configure screen. One button
allows the user to
scan a hard drive for music files, which are loaded into an internal
database. As this process
takes a significant amount of time, I've placed the code that does the
scanning in a separate
thread. In order to make it obvious that things are happening, the scan
thread uses SetDlgItemText
to update display the current file being scanned on the dialog. This all
works quite well.

The problem comes in if the user tries to dismiss the configure
dialog. Ideally, when the button
is clicked, the code should signal the thread to quit, and then do a join
for wait for it to finish before
destroying the owning object. Unfortunately, because of the way the
Windows UI works, this
instead causes a deadlock.

Basically, the trouble is that clicking the button that dismisses the
dialog calls the Window Procedure
from the message queue. Thus, while we are handling this button, no other
messages get processed.
Normally, this would be ok, as the thread should die within a few hundred
milliseconds at most. The
trouble is, though, that SetDlgItemText works by putting a message in the
queue and then waiting for it
to be processed. But the message won't be processed until the current
message handler returns.
The upshot of this is that the threads deadlock when join() is called.

This is a common Windows problem, but it is solvable. For example, the
Windows MessageBox()
doesn't cause the rest of the system to hang if called in a message
handler. The solution is for the
main thread to process messages itself while it is waiting for the
secondary thread to finish. So
instead of doing a WaitForSingleObject() on the thread, you do a
MsgWaitForMultipleObjects()
on the thread. Then, if you are woken up for Windows messages, you process
them and then go
back to sleep. I've done this in pure Windows code, and it works well.

For my current project, I'd like to use boost::thread, though, both because
I intend to port to
Linux and also because the boost thread implementation is much easier to
deal with than the
Windows one. Unfortunately, boost::thread::join() uses
WaitForSingleObject(), which means
that this deadlock issue rears its ugly head. The only solutions I've
found short of modifying
the boost code is to just delay a few seconds and hope to God the thread
dies before the object
that owns it does. Obviously this isn't a satisfactory solution! Is there
anything else I can do?

Steve


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net