none
別スレッドのオブジェクトは明示的にGC出来ない? RRS feed

  • 質問

  • 以下はSocketプログラムのサーバー側プログラムです。
                    try {
                        TcpListener=new TcpListener(IPAddress.Any,定数.ポート番号);
                        TcpListener.Start(10000);
                        var AcceptSocket=TcpListener.AcceptSocket();//1,ここでブロックされる
                        ThreadPool.UnsafeQueueUserWorkItem(delegate(Object Socket変数_) {
                            var Socket変数=Socket変数_ as Socket;
                            var NetworkStream=new NetworkStream(Socket変数);
                            var NetworkStreamBinaryReader=new BinaryReader(NetworkStream,Encoding.Unicode);
                            using(FileStream s=new FileStream("C:\\A.txt",FileMode.Create,FileAccess.ReadWrite)){
                                Int32 全Receiveバイト数=NetworkStreamBinaryReader.ReadInt32();//2,ここでブロックされる
                            }
                        },AcceptSocket);
                    } catch(SocketException e) {
                        Debug.Print(e.Message+":AcceptSocket中に閉じた");
                        return;
                    }
                    GC.Collect(); // アクセス不可能なオブジェクトを除去
                    GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッド待機
                    GC.Collect(); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放		
    
    このコードで
                        var AcceptSocket=TcpListener.AcceptSocket();//1,ここでブロックされる
    
    でブロックされているときに、サーバーの別スレッドで
    TcpListner.Stop()
    を呼び出すとブロックされている箇所で例外が発生しcatchすることが出来ます。
    しかし
                                Int32 全Receiveバイト数=NetworkStreamBinaryReader.ReadInt32();//2,ここでブロックされる
    
    ここでブロックされているときに同じくTcpListner.Stop()するとやはりcatch出来ます。
    しかしusing内にあるsのDispose()メソッドが呼び出されません。
    それはNetworkStreamBinaryReader.ReadInt32()がブロックしたままだからusing句を抜けないからです。
    Threadクラスの場合はThread.Abortメソッドを呼べばよいと思いますがThreadPoolの場合対処法はないでしょうか?
    下の3行は全てGCしてファイナライザを呼び出します。
    これをしてもファイナライザが呼び出されません。
    これは別スレッドで生成されたオブジェクトは明示的にGC出来ないということでしょうか。
    対処法はないものでしょうか。
    2009年11月10日 8:53

回答

  • ReadInt32のブロック中にリスナをStopしてどこのTryCatchブロックがエラーをキャッチしてるんでしょう?
    TcpListenerを停止させても確立したSocketが破棄されるわけじゃないので、ReadInt32でブロックされたままになっていてusingを通過してないですよ。
    #リスナではなくSocketを閉じたり、ReceiveTimeoutでエラーを発生させればusingを抜けられます
    • 回答としてマーク 和和和 2009年11月10日 11:52
    2009年11月10日 9:53

すべての返信

  • ReadInt32のブロック中にリスナをStopしてどこのTryCatchブロックがエラーをキャッチしてるんでしょう?
    TcpListenerを停止させても確立したSocketが破棄されるわけじゃないので、ReadInt32でブロックされたままになっていてusingを通過してないですよ。
    #リスナではなくSocketを閉じたり、ReceiveTimeoutでエラーを発生させればusingを抜けられます
    • 回答としてマーク 和和和 2009年11月10日 11:52
    2009年11月10日 9:53
  • TcpLisnerだけが閉じて例外が発生すると思っていました。
    Socket.Close()で希望の動作になりました。
    Socketを親スレッドでアクセス出来るように全て保持しておく必要がありますね。

    ありがとうございまいした。
    2009年11月10日 11:52