Boost logo

Boost :

From: Patrick Dreyer (patrick.dreyer_at_[hidden])
Date: 2004-04-13 18:06:15


Markus Schöpflin wrote:

> Boosters,
>
> there are some pitfalls using boost::thread on the win32 plattform
> if DLLs are involved. As I could find nothing in the documentation
> mentioning this I would like to ask if a strong warning could be
> added, that creating threads in DllMain() or in a global object
> living in a DLL will deadlock. This is especially suprising as
> using _beginthread() or CreateThread() does work in such places.
>
> The problem is, when boost::thread creates a thread it explicitly
> waits for the start up of the newly created thread. But if the
> creator of the thread itself is in DllMain() or something alike
> the newly created thread won't start until the creator leaves
> DllMain().
>
> The documentation for CreateThread() in the plattform SDK says
> the following on this subjekt: "During process startup and DLL
> initialization routines, new threads can be created, but they
> do not begin execution until DLL initialization is done for the
> process."

My knowledge tells me, that you should not do any "complex" things during the Dll initialization, including starting threads.

Have a look into the MSDN at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/dllmain.asp
There it says:

----- Begin MSDN DllMain -----
The entry-point function should perform only simple initialization or termination tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary), because this can result in a DLL being used after the system has executed its termination code.

It is safe to call other functions in Kernel32.dll, because this DLL is guaranteed to be loaded in the process address space when the entry-point function is called. It is common for the entry-point function to create synchronization objects such as critical sections and mutexes, and use TLS. Do not call the registry functions, because they are located in Advapi32.dll. If you are dynamically linking with the C run-time library, do not call malloc; instead, call HeapAlloc.

Calling imported functions other than those located in Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions in their DLLs call LoadLibrary to load other system components. Conversely, calling those functions during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.

Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.

Note: To provide more complex initialization, create an initialization routine for the DLL. You can require applications to call the initialization routine before calling any other routines in the DLL. Otherwise, you can have the initialization routine create a named mutex, and have each routine in the DLL call the initialization routine if the mutex does not exist. Be sure to use a unique mutex name for each process that loads the DLL.
----- End MSDN DllMain -----

The second last paragraph tells you why boost::thread causes a deadlock.
But as I pointed out below: try not to do any "complex" things during the Dll initialization.
I recommand to revise your design. I'm sure there is a simpler and cleaner solution than to having a thread started during the Dll initialization.

Patrick


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk