今、あるフリーソフトでハンドルリークしている事がわかりました( ´д`)
と言っても環境によっては、発生しているのかひじょーにわかりづらく、
今日まで発見が遅れたのですが。。
具体的なことはまた更新すると思いますが、ようは
WSAStartup() / WSACleanup()
を対で何回も呼んで、socket を生成しているとハンドルリークするみたいです。
今まで自分の設計としては "通信をするときだけ"
Winsock の初期化/解放をしていた のですが、
それでは問題があったようです( ´д⊂
今テストしている OS は WindowsXPPro/SP2 で、
VC6.0 SP1 Release版のマルチスレッドDLL
VC2005 SP1 Release版のマルチスレッドDLL
でコンパイル/リンクした exe でダメだったので、たぶん 全 Windows で同じ
結果になると思います。
ソースのイメージとしては以下のとおり
- #include <Winsock2.h>
- #include <Windows.h>
- #include <process.h>
UINT ConnectThread()
{
SOCKET s;
s = socket( ... );
// TCP でサーバと通信する
closesocket(s);
_endthreadex(0);
return 0;
}
- UINT ManagerThread()
- {
- HANDLE h[4];
- int i, ret;
- while( true ){
- // WinSock の初期化 ここだ!
- WSADATA wsa;
- ret = WSAStartup( MAKEWORD(2,0), &wsa );
-
- // スレッドの生成
- for( i=0 ; i<4 ; i++ ){
- h[i] = (HANDLE)_beginthreadex( ConnectThread );
- }
- // スレッドの終了待機
- for( i=0 ; i<4 ; i++ ){
- WaitforSingleObject( h[i], INFINITE );
- CloseHandle( h[i] );
- }
// WinSock の解放 ここ!
WSACleanup();
Sleep( 1000 * 20 );
}
- _endthreadex(0);
- return 0;
- }
- int main( int argc, char* argv[] )
- {
- HANDLE h = (HANDLE)_beginthreadex( ManagerThread );
- WaitforSingleObject( h, INFINITE );
- CloseHandle( h );
- return 0;
- }
|
簡単に説明するとまず、
マネージャスレッドというのが、メインスレッドから生成されます。
そしてマネージャスレッドからは、実際にコネクション処理を実行する
コネクションスレッドを4つほど生成させます。
そのコネクションスレッドの中でソケットのクライアント側をコーディングする
わけです。
そこでは非常に単純で、socket() connect() send() recv() shutdown()
closesocket() を順にやっていくだけです。
蛇足ですが、実際はエラー処理をもっと組み込んでいます。
そしてそのプログラムを1時間~4時間ほど実行すると、、
落ちます。
チェックの手順としては、タスクマネージャー等で本プロセスを監視していると、
ほんのちょっとずつ・・・ハンドルリークしていってる
のがわかります。
これを回避するには、ソースの中でここ!と書いてる箇所をループの外に出せば
回避可能になります。
私の憶測も含まれてますが、
WSAStartup() は何回コールしても良い → msdn かどっかでもそうあった
WSAStartup() / WSACleanup() のセットはプロセスで1回のみが良い→結論