4

I have thread A that is creating another thread B, than thread A is waiting using WaitForSingleObject to wait until thread B dies.

The problem is that even though thread B returns from the thread's "thread_func", thread A does not get signaled!.

I know that because I added traces (OutputDebugString) to the end of the thread_func (thread B's main function) and I can see that thread B finishes its execution, but thread A never comes out of the WaitForSingleObject.

Now, I must also add that this code is in a COM object, and the scenario described above is happening when I'm calling regsvr32.exe (it get stuck!), so I believe that thread A is coming from the DLLMain.

Any ideas why thread A does not get signaled ?!?!

Anders Abel
  • 67,989
  • 17
  • 150
  • 217
TCS
  • 5,790
  • 5
  • 54
  • 86

2 Answers2

14

You could be hitting a problem with the loader lock. Windows, has an internal critical section that gets locked whenever a DLL is loaded/unloaded or when thread is started/stopped (DllMain is always called inside that lock). If your waiting thread A has that critical section locked (i.e. you are waiting somewhere from DllMain), while another thread B tries to shutdown and attempts to acquire that loader critical section, you have your deadlock.

To see where the deadlock happens, just run your app from the VS IDE debugger and after it gets stuck, break execution. Then look at all running threads, and note the stack of each one. You should be able to follow each stack and see what each thread is waiting on.

DXM
  • 4,413
  • 1
  • 19
  • 29
  • You are absolutely right!!! I didn't know its working this way! So I guess I'll use another event to signal the end thread B thread. – TCS Jul 24 '11 at 19:30
  • +1 on this answer. Having DllMain invoke any non-trivial code path (including code that makes system and API callS) is just asking for trouble. – selbie Jul 26 '11 at 04:19
4

I think @DXM is right. The documentation on exactly what you can or can't do inside of DllMain is sparse and hard to find, but the bottom line is that you should generally keep it to a bare minimum -- initialize internal variables and such, but that's about it.

The other point I'd make is that you generally should not "call" regsvr32.exe -- ever.

RegSvr32 is basically just a wrapper that loads a DLL into its address space with LoadLibrary, Calls GetProcAddress to get the address of a function named DllRegisterServer, then calls that function. It's much cleaner (and ultimately, easier) to do the job on your own, something like this:

HMODULE mod = LoadLibrary(your_COM_file); 
register_DLL = GetProcAddress(mod, "DllRegisterServer"); 
if ( register_DLL == NULL) { 
        // must not really be a COM object... 
} 

if ( S_OK != register_DLL()) { 
        // registration failed. 
} 
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • sorry but I didn't get why `regsvr32` is bad and why writing own code is earier – Andriy Tylychko Jul 26 '11 at 12:51
  • You don't see the problem with creating an entire process, just to call one function? Here we have four lines of code that work. Your code to use `system` should be at least three lines, and doesn't work yet -- and by the time you do make it work will be considerably more (both more than you have, *and* more than four -- quite a bit more). – Jerry Coffin Jul 26 '11 at 14:56
  • 1
    I don't see any mentioning of `system`. Most probably OP runs regsvr32.exe from console window manually (as many of us do) to register his COM library, and it's stuck because of that system lock. So I completely don't understand how implementing additional tool just to register this COM library can be helpful or even relevant to the question. Your methods will do the same and his library will be stuck the same – Andriy Tylychko Jul 26 '11 at 15:37