3

I'm trying to prevent multiple calls to a DLL initialization function by using a std::lock object.

While using a program like this on a stand alone program works:

#include <mutex>
std::mutex mtx;

void main(){
  mtx.lock();
  (...)
  mtx.unlock()
}

This exact same code cannot get past the mtx.lock() when called on a DLL.

BOOL APIENTRY DllMain(HANDLE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved)
{
    f_Init(VERSION_ID);
    return TRUE;
}

//On another cpp file, a static library actually.
#include <mutex>
std::mutex mutex_state;
void f_Init(DWORD version){
    //Acquire the state lock
    mutex_state.lock(); //<-- Will NOT get past this line
    (...)
    mutex_state.unlock();
}

Why is it imposible to lock the mutex on this situation?

I'm currently using Microsoft Visual Studio 2013.

NeonMan
  • 623
  • 10
  • 24
  • Yes, pretty much the same question. Also, if D Schwartz (below) is right, the lock on the DLLMAIN is not needed. – NeonMan Jul 07 '14 at 00:36
  • For reference, Microsoft Connect [bug report](http://connect.microsoft.com/VisualStudio/feedback/details/809005/deadlock-when-locking-std-mutex-during-dllmain-static-initialization) that was closed as *by design*. – Praetorian Jul 07 '14 at 00:41
  • What does your actual initialization consist of? Most likely, it's things that should not be done in `DllMain`. (See [this article](http://blogs.msdn.com/b/oldnewthing/archive/2004/01/27/63401.aspx) for why `DllMain` should be minimal.) – David Schwartz Jul 07 '14 at 00:42

1 Answers1

0

The mutex is not needed. Access to DllMain is serialized by the implementation.

Access to the entry point is serialized by the system on a process-wide basis. Threads in DllMain hold the loader lock so no additional DLLs can be dynamically loaded or initialized. -- DllMain Entry Point

Your code deadlocks deadlock when you enter DllMain because you already hold locks. Trying to acquire additional locks while holding some unknown combination of locks is very, very likely to deadlock. You should never acquire any additional locks inside DllMain.

Consider, for example, if some additional DLL needs to be attached to lock the mutex. Two DLL's cannot be attached at the same time, and your DLL is being attached. Locking a mutex for the first time may require allocating memory and allocating memory may require attaching DLL's -- so don't do that in DllMain.

By the way, these same painful restrictions apply to constructors and destructors for global objects.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278