3

私は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ソースを呼び出すことができ、DLLAは関数自体を呼び出すこともできます。

しかし、現時点ではこれは当てはまりません。DLLAが関数自体を呼び出すか、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用にコンパイルされ、デバッグモードになっています。次のオプションを使用して、ブーストをDLLにコンパイルします(bcpを使用して使用するライブラリのファイルを取得します)。

プリプロセッサ:

  • WIN32
  • BOOST_ALL_NO_LIB
  • BOOST_ALL_DYN_LINK
  • BOOST_THREAD_BUILD_DLL
  • _DLL
  • _デバッグ
  • _ウィンドウズ
  • _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はタイムスタンプを解析しようとしているようです。そうすることで文法がインスタンス化され、それが南に向かっているように見えます。

助けてくれてありがとう:)

4

1 に答える 1

1

次のチケットがブーストのトラックで開かれているのを見つけました: boost::call_once は再入可能ではありません (少なくとも win32 では)

call_once は再入可能ではなく、再帰的に呼び出すべきではないと言っています。したがって、私が採用しているコードは未定義の動作です。チケットは「修正されません」とマークされました。

私が取った解決策は、PreProcessSource 関数のみを含む別の DLL を作成することでした。

于 2012-06-23T12:23:13.997 に答える