2

私はWindowsVista/ Sevenで非常にうまく機能するac#コードを持っていますが、WindowsXPでは機能しません。

問題のある部分は「マルチキャスト」ノードであり、基本的にマルチキャストアドレス+ポートを介してデータを読み書きします。

ネットワークに対して読み取り/書き込みを行う部分はシングルトンです。

このシングルトンにアクセスするすべてのスレッドは、いつリッスンを開始する必要があるか、いつ停止するかを示す必要があります。

ソケットは、少なくとも1つのスレッドが「開始」する必要があるときにリッスンされ、すべてのスレッドが「停止」するときに停止します(Startメソッドが返すGuidトークンを指定する必要があります)。

この開始/停止メカニズムは、ネットワーク上で何が起こっているかをスレッドが確認する必要がない場合に、そのためにメモリを消費しないようにするためのものです。

私が得た問題は、WindowsXPで次の例外が発生したことです。

System.Net.Sockets.SocketException (0x80004005): The I/O operation has been aborted because of either a thread exit or an application request
   at System.Net.Sockets.Socket.EndReceiveFrom(IAsyncResult asyncResult, EndPoint& endPoint)
   at System.Net.Sockets.UdpClient.EndReceive(IAsyncResult asyncResult, IPEndPoint& remoteEP)

いくつかの検索の後、Windows XP以下では、スレッドが終了すると、OSはすべてのI/Oリソースを解放するように見えます。(VB.NET 3.5 SocketExceptionは展開では発生しますが、開発マシンでは発生しません)。

この動作を回避する方法はありますか?私の場合、実行が終了する前に終了するスレッドを作成するのは正常であり、多くの場合、そのソケットを解放したくないのでしょうか。

それが不可能な場合、これをどのように処理しますか?

4

3 に答える 3

2

非同期操作の呼び出しスレッドは、操作が完了する前に終了します。

非同期I/O操作は、IOCP(I / O完了ポート)と呼ばれるメカニズムを使用して、I/O操作が終了したときに実行中のスレッドに通知します。

舞台裏では、すべてがオーバーラップされたI/Oと呼ばれるものに基づいています。Windows Vistaでは、オーバーラップしたI / Oの動作が変更されたため、呼び出し元のスレッドが中止されても、I/O操作はキャンセルされなくなりました。

Windows Vista(たとえば、XP)より前では、呼び出し元のスレッドが中止されるたびに、このスレッドによって開始された重複するI / Oがキャンセルされ、おそらくこれがこの例外の理由です。

あなたはここでそれについてもっと読むことができます:http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html

この動作をオーバーライドすることはできませんが、作成中のスレッドがアクティブでなくなったI / Oリソースを使用しようとしないように(たとえば、イベントを使用して)確認できます。

于 2013-03-25T13:20:30.800 に答える
1

したがって、これは、スレッドが終了したときにスレッドによって作成されたリソースを自動的に解放するWindows XPが原因であると思われます(展開ではVB.NET 3.5 SocketExceptionですが、開発マシンでは解放されません)。

したがって、私の回避策は、IsBackgroundプロパティがtrueに設定されているスレッド、つまりBlockingCollectionで反復処理するスレッドを作成することです。もう1つのIPをリッスンする必要がある場合は、このIPをブロッキングコレクションに追加すると、このスレッドがそれを作成します。

このスレッドはアプリケーションの存続期間全体で終了することはないため、リソースは解放されません。この動作をチェックしEnvironment.OSVersion.Version.Majorて、Vistaのバージョン番号である6以上になるようにしました。

今ではすべてのバージョンでチャームのように機能します

于 2013-04-26T13:54:51.673 に答える
0

新しい.NETFrameWorkバージョンでは、これでうまくいきます。

TaskEx.Run(() => _udp.BeginReceive(AsyncCallback, state)).ConfigureAwait(false);
于 2015-05-19T09:18:55.833 に答える