1

Am in the process of migrating my project to the c++11 standard with msvc110, unfortunately a thread variable, used on a dll, is behaving different from what the boost version I had.

So, originally this was working on msvc90, basically the Dll calls an InitDll where a thread was created. The thread basically served as a listener along with the main thread of the dll. Now when I create the thread it hangs and does nothing, not even executing the function which was used to initialize the thread.

Could you help me explaining how can I get same behavior as for the boost version?

EDIT: THE CODE

Sorry, couldn't reply the code on the comments

An application uses a logger through a dll. To use the logger in a very simple console application goes like this

#include <Somewhere/Logger.h>

int main()
{
    COOL_LOGGER("Here we go logging on console!");

return 0;
}

We can discuss about the way the code is written (taken from the demos I mentioned), but how is initialized the dll and thread is:

#include "Logger.h"

#ifdef _WIN32

BOOL APIENTRY DllMain( HMODULE hModule,
                   DWORD  ul_reason_for_call,
                   LPVOID lpReserved
                 )
{
switch (ul_reason_for_call)
{
     case DLL_PROCESS_ATTACH:
    TheLog::InitLog();
            break;
     case DLL_THREAD_ATTACH:
    break;
         case DLL_THREAD_DETACH:
    break;
     case DLL_PROCESS_DETACH:
    break;
}
    return TRUE;
 }

 #endif


 #include <thread>

 void InitLog()
 {
// Do the init taken from library demos
 std::thread m_thread(LogListener);
 }

 void LogListener()
 {
while(!bAppEnd)
{
    std::cin>>str;
    // change log behavior according to the user input
}
 }


 // to stop the thread when shutting down
 void EndLog()
 {
     // retrieve thread thought id or some other way
     thread.join();
 }
notNullGothik
  • 432
  • 5
  • 20
  • 2
    You should post some code. However, it sounds like you might be doing this init in `DllMain()`. Performing significant work in `DllMain()` is a perilous endeavor. See the remarks section of the docs: http://msdn.microsoft.com/en-us/library/ms682583.aspx and http://blogs.msdn.com/b/oldnewthing/archive/2004/01/27/63401.aspx or http://blogs.msdn.com/b/oldnewthing/archive/2004/01/28/63880.aspx – Michael Burr Feb 18 '13 at 18:26
  • Thank you Micheal, very true. I read about doing fancy stuff on DllMain, regardless I haven't really invented the wheel here. I just took the code as a reference from the samples dll_and_exe, of the logging library http://torjo.com/log2/doc/html/index.html – notNullGothik Feb 18 '13 at 22:29
  • Haven't changed any particular behavior since I implemented it while ago, it works nice so far. Would you recommend me the right way of initializing the library? I remember struggling a bit with that, trying to remove the init from DLLMain and calling it somewhere else, will post more if I remember what was the exact problem. – notNullGothik Feb 18 '13 at 22:32
  • the problem for reads of your question (or at least me) is that it's very unclear what DLLs are involved and what the `InitDll` being called is or what context it's being called in. you also talk about "the main thread of the DLL" which isn't a term with a standard meaning (a process might have a main thread, but a DLL doesn't). So like I said, some example code might be helpful. It should be enough to make things clear, but not so much that someone would have to put a ton of effort to understand. – Michael Burr Feb 18 '13 at 22:36
  • Sorry Micheal, I was extracting the important stuff from code, there is edited in the question – notNullGothik Feb 18 '13 at 22:51
  • 1
    I don't see anything about `dll_and_exe` (or even about DLLs) on the logging library page you linked to. However, I think you can get a good idea of if the problem is in a `DllMain()` caused deadlock by moving the call to `TheLog::InitLog();` outside of `DllMain()` and into a C function that's exported by the DLL. Then call that exported function from `main()`. – Michael Burr Feb 19 '13 at 01:39
  • Am checking that of the c function export. Meanwhile if you really want to take a look to the dll_and_exe sample, am afraid you have to download the lib, is very light, give it a try http://torjo.com/log2/ – notNullGothik Feb 19 '13 at 02:29
  • Good, exporting to the C function works. The LogListener gets called, but am getting a very suspicious result. Creating the thread as was written above simply calls the function and crash; but creating the thread variable as a pointer works as a charm. Any thoughts? I guess I will have to live with the external call of InitLog from main, didn't want to have it like that :( – notNullGothik Feb 19 '13 at 02:41

2 Answers2

3

If things go wrong in DllMain then you are severely limited in what you can do --- often the Windows loader will just terminate the app, and error handlers are often not called.

A hang suggests that the code is doing something that requires loading a DLL, or is waiting for another DLL to initialize, neither of which can happen until the call to DllMain for this DLL is finished. It is possible that the implementation of std::thread is doing one of these things.

Edit: One way to avoid the problem is to use std::call_once in every exported function that communicates with this background thread, to ensure that the thread is started. That way you are not using std::thread in DllMain, but you don't need to expose an "init" function.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
  • Thank you, it seems so. I will stick to a init call from main, as I previously stated on the comments above. Didn't want to expose this to users, but I currently see no workaround. – notNullGothik Feb 19 '13 at 15:15
2

Your InitLog function has a thread that appears scoped to that function. When the function exits, which it does immediately, the thread is destroyed. However, destruction of an unjoined std::thread (but not boost::thread?) calls std::terminate. Put in a terminate handler if you want to test that that's what's happening.

metal
  • 6,202
  • 1
  • 34
  • 49
  • I believe recent versions of Boost.Thread [align with](http://stackoverflow.com/q/11393936/283302) the behavior of an unjoined `std::thread` – Sam Miller Feb 19 '13 at 02:40
  • Right. Not sure about older versions. Considering that the OP mentions VS 9.0 (aka 2005), Boost may also be of older vintage. – metal Feb 19 '13 at 02:47
  • I took care of having latest libraries with the migration process, boost_1_53_0. – notNullGothik Feb 19 '13 at 02:54
  • @metal no luck creating the terminate handler, i don't get a call for it – notNullGothik Feb 19 '13 at 03:05
  • 2
    Ok, but the code as shown is certainly incorrect. Make that a std::unique_ptr at file scope, and then initialize it in your init function so that it is persistent. And do be sure to join it at the end. – metal Feb 19 '13 at 03:09
  • Hmmm it hangs the same... Thread variable at file scope std::unique_ptr m_thread = NULL; Then on init m_thread.reset( new std::thread(LogListener)); I tried initializing on declaration also with same results – notNullGothik Feb 19 '13 at 03:24
  • Anthony Williams responded here also. He's the guru on this topic. Listen to him. :-) – metal Feb 19 '13 at 13:44