1

共有ライブラリでは、関数 func1() に atexit(terminate_global) があり、この共有ライブラリには「属性((コンストラクタ))」と「属性((デストラクタ))」 がありません。
したがって、プログラム フローは次のようになります。
1) アプリケーションは、dlopen を使用して共有ライブラリを読み込みます。
2) アプリケーションは、dlsym を使用して func1() を呼び出します。
3) func1() には atexit(terminate_global) があります。
4) func1() が戻ります。
5) アプリケーションは dlclose を呼び出して、ライブラリの割り当てを解除します。

上記の手順では、ライブラリがアンロードされたときに atexit() が呼び出されていません。では、共有ライブラリの割り当てを解除するときに atexit() を呼び出す必要がある場合、正しい方法は何でしょうか? atexit 登録関数を呼び出せるように、属性((コンストラクタ)) および属性((デストラクタ)) 関数属性を使用してルーチンをエクスポートする必要がありますか?

4

1 に答える 1

0

terminate_globalに渡される関数atexitはプラグインで定義されていると仮定します。がメイン プログラムterminate_globalによって定義されたグローバル関数である場合(プラグインにアクセスするシンボルを取得するためにフラグでリンクされている)、プラグインは を呼び出すことができますが、それを行う API 関数を提供します。-rdynamicatexit(terminate_global)

アプリケーションがプラグインを決して-ing しないことが確実でない限り、私はそれをしません (プラグ インによって定義された関数であるプラグインatexit(terminate_fun) 内で呼び出します)。terminate_fun dlclose

アプリケーションがどこかで-ing 関数dlcloseの外側で呼び出している可能性があり、後で処理するときにクラッシュする場合 (登録された関数へのポインタが無効でマップされていないため)atexitdlclosemunmapplugin.soexitatexitatexit

dlcloseプラグインの担当者を定義する必要があります。アプリケーションが明示的にそれを行っている場合、C 関数 (またはプラグイン内のいくつかの静的 C++ データのデストラクタ) によって何らかのクリーンアップを実行するか__attribute__((destructor))または( )で得られるものには、そのクリーンアップ関数が適切に呼び出されます。plugin_cleanupdlsym

別の方法として、プラグインがアプリケーションによって明示的に dlclose-d されないことを定義して文書化することもできます (特にクリーンアップ機構を提供している場合は、これで問題ないことがよくあります)。しかし、それはvalgrind不幸なことかもしれません。

于 2015-03-30T12:06:57.727 に答える