2013-02-18 2 views
1

В процессе переноса моего проекта на стандарт C++ 11 с помощью msvc110, к сожалению, переменная потока, используемая в dll, ведет себя отличную от той версии, которая была у меня в версии.C++ 11 thread vs boost thread

Итак, первоначально это работало на msvc90, в основном Dll вызывает InitDll, где был создан поток. Поток в основном служил слушателем вместе с основным потоком DLL. Теперь, когда я создаю поток, он зависает и ничего не делает, даже не выполняя функцию, которая была использована для инициализации потока.

Не могли бы вы помочь мне объяснить, как я могу получить такое же поведение, как и для ускоренной версии?

EDIT: КОД

К сожалению, не смог ответить код на комментарии

Приложение использует регистратор через DLL. Чтобы использовать регистратор в очень простом консольном приложении идет как этого

#include <Somewhere/Logger.h> 

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

return 0; 
} 

Мы можем обсуждать о том, как код написан (взято из демки я упоминал), но как инициализируется DLL и нитки является:

#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(); 
} 
+2

Вы должны ввести код. Однако, похоже, вы можете сделать этот init в 'DllMain()'. Выполнение важной работы в 'DllMain()' является опасным делом. См. Раздел замечаний в документах: http://msdn.microsoft.com/en-us/library/ms682583.aspx и http://blogs.msdn.com/b/oldnewthing/archive/2004/01/27/ 63401.aspx или http://blogs.msdn.com/b/oldnewthing/archive/2004/01/28/63880.aspx –

+0

Спасибо, Мишель, очень прав. Я читал о том, как делать причудливые вещи на DllMain, несмотря на то, что я здесь не изобрел колесо. Я просто взял код в качестве ссылки из образцов dll_and_exe, библиотеки журналов http://torjo.com/log2/doc/html/index.html – notNullGothik

+0

Не изменил какого-либо конкретного поведения, так как я его реализовал некоторое время назад, это работает до сих пор. Вы порекомендовали бы мне правильный способ инициализации библиотеки? Я помню, что немного борюсь с этим, пытаясь удалить init из DLLMain и называя его где-то в другом месте, будет размещать больше, если помню, что было точной проблемой. – notNullGothik

ответ

2

У вашей функции InitLog есть поток, который отображается в этой функции. Когда функция выходит, что она делает немедленно, поток уничтожается. Однако уничтожение unjoined std :: thread (но не boost :: thread?) Вызывает std :: terminate. Поместите обработчик завершения, если вы хотите проверить, что это то, что происходит.

+0

Я считаю, что последние версии Boost.Thread [align with] (http://stackoverflow.com/q/11393936/283302) поведение невыполненного 'std :: thread' –

+0

Право. Не уверен в более старых версиях. Учитывая, что OP упоминает VS 9.0 (aka 2005), Boost также может быть старшего урожая. – metal

+0

Я позаботился о с последними библиотеками с процессом миграции, boost_1_53_0. – notNullGothik

3

Если все пошло не так в DllMain, то вы сильно ограничены в том, что вы можете сделать - часто загрузчик Windows просто прекращает приложение, а обработчики ошибок часто не вызывают.

A hang предполагает, что код выполняет то, что требует загрузки DLL, или ожидает, что другая DLL будет инициализирована, ни одна из которых не может произойти до тех пор, пока вызов для DllMain для этой DLL не будет завершен. Возможно, что реализация std::thread делает одну из этих вещей.

Редактировать: Один из способов избежать проблемы - использовать std::call_once в каждой экспортируемой функции, которая связывается с этим фоновым потоком, чтобы гарантировать, что поток запущен. Таким образом, вы не используете std::thread в DllMain, но вам не нужно выставлять функцию «init».

+0

Спасибо, похоже. Я буду придерживаться вызова init из main, как я уже говорил выше. Не хотел показывать это пользователям, но в настоящее время я не вижу обходного пути. – notNullGothik

+0

Вы можете использовать 'std :: call_once', как описано в моем редактировании. –