atExit 関数で WSACleanup を登録してもよろしいですか? コード内のさまざまなポイントで終了できるアプリケーションがいくつかあるため、コード全体で WSACleanup を配置することは避けたいと考えています。現在、これらすべてのアプリケーションで使用される dll があるため、DllMain を介して WSAStartup / WSACleanup を呼び出しています。ただし、Microsoft は、デッドロックが発生する可能性があるため、DllMain を介して WSAStartup / WSACleanup を使用しないことを強く推奨しています。WSAStarup を DllMain から移動し、Windows ソケット ライブラリにアクセスする前に、すべてのアプリケーションのコード内のある時点でこれを呼び出すことができます。そして、WSAStartup を呼び出すとすぐに、atExit 関数を使用して WSACleanup への呼び出しを登録します。誰もこのアプローチの経験がありますか? ありがとう!
3 に答える
マルチスレッド アプリがあり、一部のスレッドがまだ接続されている場合、相手側のアプリケーションは接続の終了方法を気に入らない場合があります。そのため、main() が終了する前にすべての通信を順番に終了することが望ましいです。終了したら、WSACleanup を呼び出すこともできます。
RAII アプローチが好ましいことに同意します。
ただし、警告の言葉: dll とハンドルが混在する atExit は、Windows では壊れています。残念ながら、これは C++ ランタイムによって atExit ハンドラーで実装されるため、RAII にも影響します。
ウィンドウで atexit ハンドラーが呼び出される順序:
- どこかで exit が呼び出されるか、main() がスコープ外になります
- プロセスで定義された atexit ハンドラが呼び出されます。
- すべてのハンドルが破棄されます。
- dll で定義された atexit ハンドラが呼び出されます。
dll 内の atexit ハンドラーがプロセス内のハンドラーの前に登録されているかどうかは問題ではありません。プロセス ハンドラーが最初に呼び出され、dll ハンドラーが呼び出される前にハンドルが破棄されます。これにより、dll が所有するすべてのハンドルが有効でなくなったため、クリーンアップ コードが呼び出されると、win32 例外が発生します。
これは、スレッド、ミューテックス、ファイル、ソケットなどへのハンドルを保持するコードに影響します。それらが dll に割り当てられている場合、exit が呼び出される前にそれらをクリーンアップするか、まったくクリーンアップする必要があります。
ところで、私はアンチ ウィンドウではありません。私が間違っている場合、または誰かがこれを回避する方法を知っている場合は、アプリケーションのクリーンアップに計り知れない苦痛が生じるため、知りたいと思います。これは、アプリケーションの終了時に win32 例外を取得した後、C++ ランタイムで終了処理をデバッグすることであることがわかりました。
コードを終了するには、すべての呼び出しを削除する必要がありました。これで、DLL 内の静的データがハンドルを制御しないことが保証されました。すべての静的ハンドルは、メインがスコープ外になると破棄されるオブジェクトによって制御されます。
さて、atExitは使用すべきではないと思います。クラス内のソケットライブラリの初期化と破棄のラッピングというRAIIの原則に従う必要があります。