4

起動時にフリーズする GCC でコンパイルされた C++ プログラムをデバッグしようとしています。GCC ミューテックスは関数の静的ローカル変数を保護しますが、そのようなロックを取得するのを待っていることが原因でフリーズしているようです。これがどのように起こるかはかなり混乱します。最初のモジュール A の静的初期化が発生し (GCC が呼び出す __static_init 関数がバックトレースに表示されます)、静的ローカル変数を持つ関数 Foo() が呼び出されます。静的ローカル変数は、コンストラクターが関数のいくつかのレイヤーを介して呼び出すオブジェクトであり、突然バックトレースにいくつかの ?? があり、2 番目のモジュール B の静的初期化にあります (__static 関数が何度も発生します)。 、その後 Foo() を呼び出しますが、Foo() が最初に返されなかったため、ローカル静的変数のミューテックスがまだ設定されており、ロックされています。

ある静的初期化が別の静的初期化をトリガーするにはどうすればよいですか? 私の最初の理論は共有ライブラリでした。モジュール A がモジュール B の関数を呼び出して、モジュール B をロードし、B の static init をトリガーするというものでしたが、そうではないようです。モジュール A はモジュール B をまったく使用しません。だから私は2番目の(そして恐ろしい)推測をしています。と言う:

  1. モジュール A は、テンプレート化された関数またはテンプレート化されたクラスの関数を使用します。foo<int>::bar()

  2. モジュール B も使用foo<int>::bar()

  3. モジュール A はモジュール B にまったく依存していません

  4. リンク時に、リンカーには の 2 つのインスタンスがありますがfoo<int>::bar()、テンプレート関数は弱いシンボルとしてマークされているため、これは問題ありません...

  5. モジュール B はモジュール A に依存していませんが、実行時にモジュール A が を呼び出しfoo<int>::bar、モジュール B の static init がトリガーされます。なんで?リンカーは、リンク時にモジュール A のインスタンスではなく、モジュール B の foo::bar のインスタンスを使用することを決定したためです。

この特定のシナリオは有効ですか? それとも、あるモジュールの static init が別のモジュールで static init をトリガーすることはありませんか?

明確化: GCC はミューテックスを自動的に作成して、関数の静的変数を保護します。私はミューテックスで何もしていません。これは、関数の静的変数をスレッドセーフにする GCC の方法です。

更新:静的初期化は翻訳単位間で定義されておらず、順序に依存すべきではないことを知っています。しかし、問題をデバッグする手がかりとして、これが通常の動作であるかどうかに興味があります。コンパイラがこれを行うコードを生成するのは正常ですか、それとも GCC のバグを示している可能性がありますか?

4

2 に答える 2

4

「静的初期化順序の大失敗」へようこそ。この問題がどのように発生し、どのように修正するかを(詳細に)説明しているので、おそらくその記事全体を読む必要があります。

于 2010-04-15T05:58:55.557 に答える
2

ビルは効果的な C++ 項目 4 を引き出します

異なる翻訳単位で定義された非ローカル静的オブジェクトの初期化の順序は定義されていません

簡単に言えば、コンパイラはやりたいことを何でも実行できます。

于 2010-04-15T00:44:11.420 に答える