このような状況では、別のスレッドからストリーム リーダーを終了するだけです。リーダーを閉じると、ループが壊れます。余分な同期キューを通過することは、不必要に行うボイラープレートが増えるだけです。最終的にどこかで、ブロッキング リーダーを停止する必要があります。値をキューに入れると、コンシューマーがブロックされるのを防ぐだけで、リーダーはブロックされません。
以下は、ソケット ブロッキング読み取りの例です。意図的に送信しない 1 バイトの読み取りをブロックします。数秒後、ソケットを破棄します。ソケットはブロッキング読み取りから解放され、アプリは正常に終了します。各スレッドが何を行っているか、いつ発生したかをログに記録します (各ログ行の前に付いている数字はスレッド ID であり、個別のスレッドをインデントします)。
ブロッキング リーダーを使用するクラスでは、Disposable パターンを実装し、そこでリーダーを閉じる/破棄する必要があります。
static void Main(string[] args)
{
SocketTest();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
public static void SocketTest()
{
int port = 22345;
var tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
// Listening thread
new Thread(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - Waiting for connection to port");
var socket = tcpListener.AcceptSocket();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - Connection accepted");
var stream = new NetworkStream(socket);
var reader = new BinaryReader(stream);
try
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - Starting blocking read");
var bytes = reader.ReadBytes(1);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - Done blocking read, read {0} bytes", bytes.Length);
}
catch (Exception ex)
{
Console.WriteLine("Error reading " + ex);
}
}).Start();
// connecting thread
new Thread(() =>
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("\t" + Thread.CurrentThread.ManagedThreadId + " - Connecting to local port");
socket.Connect("127.0.0.1", port);
Console.WriteLine("\t" + Thread.CurrentThread.ManagedThreadId + " - Connecting to local succeeded");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("\t" + Thread.CurrentThread.ManagedThreadId + " - Disposing of socket");
socket.Dispose();
}).Start();
Thread.Sleep(TimeSpan.FromSeconds(5));
}
これを実行すると、次のようになります。
3 - Waiting for connection to port
4 - Connecting to local port
4 - Connecting to local succeeded
3 - Connection accepted
3 - Starting blocking read
4 - Disposing of socket
3 - Done blocking read, read 0 bytes
Press any key to exit
あなたはここで質問に答えました:
私の考えは、別のスレッドで removeServerResponseStream.Read を持つことでした
これはまさにあなたがすべきことです。アプリが閉じていることがわかったら、アクティブなスレッドからソケットを閉じます。これでブロックされたスレッドが解放され、正常に終了できます。
ここでのパターンは、通常、特定のソケットのスレッドをスピンアップし、要求用の一種の「コントローラー」スレッドである 1 つのアクティブなスレッドを維持することです。