C++ 为什么从DLL调用boost::wave::context构造函数时会死锁?

C++ 为什么从DLL调用boost::wave::context构造函数时会死锁?,c++,boost,dll,C++,Boost,Dll,我有一个名为PreProcessSource的函数,它分配boost::wave::context并进行一些预处理;一点也不奇怪 std::string PreProcessSource(const std::string& instring, const std::string& defines) { typedef boost::wave::cpplexer::lex_token<> token_type; typedef boost::wave:

我有一个名为PreProcessSource的函数,它分配boost::wave::context并进行一些预处理;一点也不奇怪

std::string PreProcessSource(const std::string& instring, const std::string& defines)
{
    typedef boost::wave::cpplexer::lex_token<> token_type;
    typedef boost::wave::cpplexer::lex_iterator<token_type> lex_iterator_type;
    typedef boost::wave::context<std::string::iterator, lex_iterator_type> context_type;

    std::string source = instring;
    context_type ctx(source.begin(), source.end()); // DEADLOCK here
    ctx.set_language(boost::wave::enable_emit_line_directives(ctx.get_language(), true));

    if(!defines.empty())
    {
        std::vector<std::string> tokens;
        Split<std::string>(defines, tokens, ",");

        std::vector<std::string>::const_iterator cit = tokens.begin();

        for (;cit != tokens.end(); ++cit)
            ctx.add_macro_definition(*cit);
    }

    context_type::iterator_type first = ctx.begin();
    context_type::iterator_type last = ctx.end();

    std::string outstring;

    while (first != last)
    {
        const token_type::string_type& value = (*first).get_value();
        std::copy(value.begin(), value.end(), std::back_inserter(outstring));
        ++first;
    }

    return outstring;
}
代码针对x64编译,并处于调试模式。 我使用以下选项将boost编译成DLL(使用bcp获取我使用的库的文件):

预处理器:

  • WIN32
  • 增强所有的无库
  • 增强所有动态链接
  • BOOST\u线程\u构建\u DLL
  • _动态链接库
  • _调试
  • _窗户
  • _USRDLL
代码生成:

  • C++异常(/EHsc)
  • 多线程调试DLL(/MDd)
  • 功能级链接(/Gy)
  • 数据流单指令多数据扩展指令集2(/arch:SSE2)(/arch:SSE2)
  • 快速浮点模型(/fp:Fast)
DLL A使用相同的选项,除了BOOST\u ALL\u DYN\u LINK、BOOST\u THREAD\u BUILD\u DLL和字符串池选项

Boost单元测试库作为静态库单独构建

以下是工作版本的堆栈跟踪:

Nitro.dll!boost::call_once<void (__cdecl*)(void)>(boost::once_flag & flag, void (void)* f)  Line 200    C++
Nitro.dll!boost::call_once(void (void)* func, boost::once_flag & flag)  Line 28 C++
Nitro.dll!boost::spirit::classic::static_<boost::thread_specific_ptr<boost::weak_ptr<boost::spirit::classic::impl::grammar_helper ...  Line 72 + 0x13 bytes C++
Nitro.dll!boost::spirit::classic::impl::get_definition<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 241 + 0x17 bytes   C++
Nitro.dll!boost::spirit::classic::impl::grammar_parser_parse<0,boost::wave::util::time_conversion::time_conversion_grammar, ...  Line 296 + 0xa bytes   C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 55 + 0x3c bytes C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 65 + 0x75 bytes C++
Nitro.dll!boost::spirit::classic::impl::phrase_parser<boost::spirit::classic::space_parser>::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar> ... Line 136   C++
Nitro.dll!boost::spirit::classic::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 155 + 0x3a bytes C++
Nitro.dll!boost::spirit::classic::parse<char,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 173 + 0x23 bytes C++
Nitro.dll!boost::wave::util::time_conversion::time_conversion_helper::time_conversion_helper(const char * act_time)  Line 123   C++
Nitro.dll!boost::wave::util::predefined_macros::predefined_macros()  Line 196 + 0x38 bytes  C++
...
Nitro.dll!Nitro::PreProcessSource(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & instring, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & defines)  Line 51 + 0xa0 bytes    C++
NitroCoreUnitTests.exe!Preprocessor::test_method()  Line 16 C++
NitroCoreUnitTests.exe!Preprocessor_invoker()  Line 7 + 0x1f bytes  C++
...
NitroCoreUnitTests.exe!boost::unit_test::unit_test_main(boost::unit_test::test_suite * (int, char * *)* init_func, int argc, char * * argv)  Line 187   C++
NitroCoreUnitTests.exe!main(int argc, char * * argv)  Line 238  C++
NitroCoreUnitTests.exe!__tmainCRTStartup()  Line 555 + 0x19 bytes   C
NitroCoreUnitTests.exe!mainCRTStartup()  Line 371   C
kernel32.dll!00000000766a652d()     
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]  
ntdll.dll!0000000076d9c521()    
Nitro.dll!Boost::Call一次(Booo::OncIh旗和旗,Vale+Valf)200行C++
Nitro.dll!Boost:(空虚(空)*FUNC,Booo::OncIh旗和旗)28线C++

Nitro.dll!boost::spirit::classic::static\up>我发现boost的trac上打开了以下票据:

它说call_once不是可重入的,不应该递归调用。因此,我使用的代码是未定义的行为;这张票被标上了“无法修复”的字样

我采取的解决方案是创建一个单独的DLL,它只包含预处理源函数

class Tutorial00 : public Game
{
public:
    // ...
    Tutorial00()
    : Game()
    {
#if !DO_DEADLOCK
        std::stringstream sstream;
        sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl;
        std::string source = sstream.str();
        std::string defines = "";
        std::string shaderCode = Nitro::PreProcessSource(source, defines);
#endif
    }

    void LoadContent()
    {
#if DO_DEADLOCK
        std::stringstream sstream;
        sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl;
        std::string source = sstream.str();
        std::string defines = "";
        std::string shaderCode = Nitro::PreProcessSource(source, defines);
#endif
        // Original code that deadlocks too.
        // Calls in the DLL, which will call PreProcessSource.
        // effect->Initialize(device, source, "DX11");
    }

    // ...
};

#if 1
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
#else
int main(int argc, char* argv[])
#endif
{
    Tutorial00 app;
    app.Run();
    return 0;
}
// In the DLL
void Game::Run()
{
    try
    {
        // ...

        LoadContent();

        // ...
    } catch(/* ... */) { }
}
Nitro.dll!boost::call_once<void (__cdecl*)(void)>(boost::once_flag & flag, void (void)* f)  Line 200    C++
Nitro.dll!boost::call_once(void (void)* func, boost::once_flag & flag)  Line 28 C++
Nitro.dll!boost::spirit::classic::static_<boost::thread_specific_ptr<boost::weak_ptr<boost::spirit::classic::impl::grammar_helper ...  Line 72 + 0x13 bytes C++
Nitro.dll!boost::spirit::classic::impl::get_definition<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 241 + 0x17 bytes   C++
Nitro.dll!boost::spirit::classic::impl::grammar_parser_parse<0,boost::wave::util::time_conversion::time_conversion_grammar, ...  Line 296 + 0xa bytes   C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 55 + 0x3c bytes C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 65 + 0x75 bytes C++
Nitro.dll!boost::spirit::classic::impl::phrase_parser<boost::spirit::classic::space_parser>::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar> ... Line 136   C++
Nitro.dll!boost::spirit::classic::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 155 + 0x3a bytes C++
Nitro.dll!boost::spirit::classic::parse<char,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 173 + 0x23 bytes C++
Nitro.dll!boost::wave::util::time_conversion::time_conversion_helper::time_conversion_helper(const char * act_time)  Line 123   C++
Nitro.dll!boost::wave::util::predefined_macros::predefined_macros()  Line 196 + 0x38 bytes  C++
...
Nitro.dll!Nitro::PreProcessSource(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & instring, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & defines)  Line 51 + 0xa0 bytes    C++
NitroCoreUnitTests.exe!Preprocessor::test_method()  Line 16 C++
NitroCoreUnitTests.exe!Preprocessor_invoker()  Line 7 + 0x1f bytes  C++
...
NitroCoreUnitTests.exe!boost::unit_test::unit_test_main(boost::unit_test::test_suite * (int, char * *)* init_func, int argc, char * * argv)  Line 187   C++
NitroCoreUnitTests.exe!main(int argc, char * * argv)  Line 238  C++
NitroCoreUnitTests.exe!__tmainCRTStartup()  Line 555 + 0x19 bytes   C
NitroCoreUnitTests.exe!mainCRTStartup()  Line 371   C
kernel32.dll!00000000766a652d()     
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]  
ntdll.dll!0000000076d9c521()    
ntdll.dll!0000000076dc135a()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
KernelBase.dll!000007fefd4f10dc()   
Nitro.dll!boost::call_once<void (__cdecl*)(void)>(boost::once_flag & flag, void (void)* f)  Line 197 + 0x18 bytes   C++
Nitro.dll!boost::call_once(void (void)* func, boost::once_flag & flag)  Line 28 C++
Nitro.dll!boost::spirit::classic::static_<boost::thread_specific_ptr<boost::weak_ptr<boost::spirit::classic::impl::grammar_helper ...  Line 72 + 0x13 bytes C++
Nitro.dll!boost::spirit::classic::impl::get_definition<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 241 + 0x17 bytes   C++
Nitro.dll!boost::spirit::classic::impl::grammar_parser_parse<0,boost::wave::util::time_conversion::time_conversion_grammar, ...  Line 296 + 0xa bytes   C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 55 + 0x3c bytes C++
Nitro.dll!boost::spirit::classic::grammar<boost::wave::util::time_conversion::time_conversion_grammar, ... Line 65 + 0x75 bytes C++
Nitro.dll!boost::spirit::classic::impl::phrase_parser<boost::spirit::classic::space_parser>::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar> ... Line 136   C++
Nitro.dll!boost::spirit::classic::parse<char const * __ptr64,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 155 + 0x3a bytes C++
Nitro.dll!boost::spirit::classic::parse<char,boost::wave::util::time_conversion::time_conversion_grammar, ... Line 173 + 0x23 bytes C++
Nitro.dll!boost::wave::util::time_conversion::time_conversion_helper::time_conversion_helper(const char * act_time)  Line 123   C++
Nitro.dll!boost::wave::util::predefined_macros::predefined_macros()  Line 196 + 0x38 bytes  C++
...
Nitro.dll!Nitro::PreProcessSource(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & instring, const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & defines)  Line 51 + 0xa0 bytes    C++
Tutorial01.exe!Tutorial01::LoadContent()  Line 70 + 0x33 bytes  C++
Nitro.dll!Nitro::Game::Run()  Line 40   C++
Tutorial01.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow)  Line 149  C++
Tutorial01.exe!__tmainCRTStartup()  Line 547 + 0x42 bytes   C
Tutorial01.exe!wWinMainCRTStartup()  Line 371   C
kernel32.dll!00000000766a652d()     
ntdll.dll!0000000076d9c521()