gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:07:56 26 4
gpt4 key购买 nike

我有一个名为 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;
}

过去(这个项目正在现代化,所以它被打破了很长时间)它曾经在相同的设置下工作得很好:

库A是一个托管PreProcess源函数的DLL,可执行文件B使用DLL A并可以调用PreProcess源,DLL A有时也可以调用函数本身。

但现在情况不再如此:无论何时 DLL A 调用函数本身,或 DLL A 调用另一个函数,后者又回调 DLL A PreProcess 源,它就会死锁。

这是一个在我的单元测试中运行良好的示例:

BOOST_AUTO_TEST_CASE(Preprocessor)
{
std::stringstream sstream;
sstream << "void main(inout float4 vtxInput : POSITION) { }" << std::endl << std::endl;
std::string source = sstream.str();
std::string defines = "";
try
{
std::string shaderCode = Nitro::PreProcessSource(source, defines);
} catch (boost::wave::preprocess_exception& pe)
{
std::cerr << pe.what() << std::endl;
}
}

奇怪的是,如果在下面的代码中将 DO_DEADLOCK 定义为 1,就会发生死锁:

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;
}

请注意,构造函数是直接从可执行文件中调用的,而 LoadContent 是从 DLL 中调用的:

// In the DLL
void Game::Run()
{
try
{
// ...

LoadContent();

// ...
} catch(/* ... */) { }
}

代码是为 x64 编译的,并且处于 Debug模式。我使用以下选项将自己编译成一个 DLL(使用 bcp 获取我使用的库的文件):

预处理器:

  • WIN32
  • BOOST_ALL_NO_LIB
  • BOOST_ALL_DYN_LINK
  • BOOST_THREAD_BUILD_DLL
  • _动态链接库
  • _DEBUG
  • _WINDOWS
  • _USRDLL

代码生成:

  • C++ 异常 (/EHsc)
  • 多线程调试 DLL (/MDd)
  • 函数级链接 (/Gy)
  • 流式 SIMD 扩展 2 (/arch:SSE2) (/arch:SSE2)
  • 快速浮点模型(/fp:fast)

DLL A 使用相同的选项,除了 BOOST_ALL_DYN_LINK、BOOST_THREAD_BUILD_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()

这里是死锁的堆栈跟踪:

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()

似乎 boost::wave 正在尝试解析某个时间戳,并通过这样做来实例化一个语法,而这正是事情似乎向南发展的时候。

在此先感谢您的帮助:)

最佳答案

我发现在 boost 的 trac 上打开了以下票证:boost::call_once not re-entrant (at least in win32)

它说 call_once 不可重入,不应该被递归调用。因此,我使用的代码是未定义的行为;票被标记为“不会修复”。

我采取的解决方案是创建一个仅包含 PreProcessSource 函数的单独 DLL。

关于c++ - 为什么从 DLL 调用时 boost::wave::context 构造函数会死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11111538/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com