これが私の状況です:
チャットサーバーに接続するためのチャットクライアントを作成しています。TcpClientを使用して接続を作成し、そこからNetworkStreamオブジェクトを取得します。StreamReaderとStreamWriterを使用して、データの読み取りと書き込みを行っています。
これが私の読み取りがどのように見えるかです:
public string Read()
{
StringBuilder sb = new StringBuilder();
try
{
int tmp;
while (true)
{
tmp = StreamReader.Read();
if (tmp == 0)
break;
else
sb.Append((char)tmp);
Thread.Sleep(1);
}
}
catch (Exception ex)
{
// log exception
}
return sb.ToString();
}
それはうまく機能し、ダンディです。私のメインプログラムでは、このReadメソッドを継続的に呼び出してデータがあるかどうかを確認するスレッドを作成します。例を以下に示します。
private void Listen()
{
try
{
while (IsShuttingDown == false)
{
string data = Read();
if (!string.IsNullOrEmpty(data))
{
// do stuff
}
}
}
catch (ThreadInterruptedException ex)
{
// log it
}
}
...
Thread listenThread = new Thread(new ThreadStart(Listen));
listenThread.Start();
これは問題なく機能します。アプリケーションをシャットダウンしたいときに問題が発生します。UIからシャットダウンコマンドを受け取り、リスニングスレッドにリスニングを停止するように指示します(つまり、この読み取り関数の呼び出しを停止します)。Joinを呼び出し、この子スレッドの実行が停止するのを待ちます。そのようです:
// tell the thread to stop listening and wait for a sec
IsShuttingDown = true;
Thread.Sleep(TimeSpan.FromSeconds(1.00));
// if we've reach here and the thread is still alive
// interrupt it and tell it to quit
if (listenThread.IsAlive)
listenThread.Interrupt();
// wait until thread is done
listenThread.Join();
問題は、実行が停止しないことです。コードにステップインしましたが、Read()メソッドがブロックしているため、リスニングスレッドがブロックしています。Read()はそこに座っているだけで、戻りません。したがって、スレッドがその1ミリ秒スリープしてから中断されることはありません。
十分な時間放置すると、別のパケットを取得してスレッドをスリープ状態にする機会が得られると確信しています(アクティブなチャットルームの場合、またはサーバーからpingを取得する場合)。しかし、私はそれに依存したくありません。ユーザーがシャットダウンと言ったら、シャットダウンしたいです!!
私が見つけた代替案の1つは、NetworkStreamのDataAvailableメソッドを使用して、StreamReader.Read()を呼び出す前にチェックできるようにすることです。信頼性が低く、サーバーからパケットを読み取るときにデータが失われたため、これは機能しませんでした。(そのため、正しくログインできなかったなど)
このスレッドを正常にシャットダウンする方法についてのアイデアはありますか?リスニングスレッドでAbort()を呼び出すのは嫌です...