ここから本文です

C#、ReadLineの待機状態を解除させるには?

jetblackersさん

2012/4/2912:46:13

C#、ReadLineの待機状態を解除させるには?

簡単な足し算をするプログラムを作っています。
前回の質問でマルチスレッドで時間制限を設ける方法を教えていただきました。
簡単に説明するとメインのスレッドで、時間を計測し次へ進む処理。サブのスレッドで入力値を取得するという方法です。
そこでまた問題が発生してしまったのですが、時間経過で進んだ場合、サブのスレッドを中断しているのですが、ReadLineでの待機状態はそのまま残ってしまいます。
そのため、1問目をタイムアップで終了し2問目に移った場合、一度エンターキーを押さないと通常の処理(回答を受け付ける)になりません。つまり最初の文字入力は無反応で、2回目は受け付けるということです。
下記のコードは前回教えていただいたものを10回ループさせたものです。


using System;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
private static string input;

static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread thread = new Thread(new ThreadStart(ReadLine));
thread.IsBackground = true;
thread.Start();

Console.Write("1 + 1 = ");

long startTime = DateTime.Now.Ticks;
input = "";

//5秒経過するか入力が有るまで待つ
while (startTime + 50000000 > DateTime.Now.Ticks && input == "") { }

thread.Abort();
thread.Interrupt();

if (input == "2")
{
Console.WriteLine("○");
}
else
{
Console.WriteLine("×");
}

Thread.Sleep(500);
}

}

static void ReadLine()
{
input = Console.ReadLine();
}
}
}


ひょっとしたら私が考えている原因ではないのかもしれませんが、どなたか解決方法を教えてください。

閲覧数:
2,128
回答数:
1
お礼:
250枚

違反報告

ベストアンサーに選ばれた回答

プロフィール画像

カテゴリマスター

trekfareastさん

編集あり2012/4/3000:07:42

/*
* jetblackersさん へ
*
* どうも、スレッドを停止しても、input = Console.ReadLine();が
* 完全に停止している訳ではないようで、これの解除方法が分からないので……
* (ダレカタスケテ…)
*
* Console.ReadLine()をタイムアウト付きエミュレート(もどき)
* してみました。
*
* C# 2010では、それなりのエミュレートになってます。(^_^;
* 2008でもうまく動くと良いのですが…
*
*/
using System;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
private static string input;

//Console.ReadLine()をタイムアウト付きエミュレート(もどき)
//(いろいろと不完全です…画面を超えるとエラーになるとか…(^_^;)
//引数:タイムアウト時間(秒)
//戻り値:入力された文字列(タイムアウトの時は空文字列)
static string MyReadLine(int second)
{
long startTime = DateTime.Now.Ticks;
ConsoleKeyInfo cki = new ConsoleKeyInfo();
string data = "";

//現在のカーソル位置を保存
int ct = Console.CursorTop;//現在のカーソルの行番号を記憶
int cl = Console.CursorLeft;//現在のカーソルの桁番号を記憶

while(true)
{
while (Console.KeyAvailable == false)
{
if (startTime + 10000000 * second < DateTime.Now.Ticks)
{
//時間切れの時
Console.WriteLine("");//強制的にEnter
return "";
}
Thread.Sleep(100); // Loop until input is entered.
}

cki = Console.ReadKey(true);
if (cki.Key == ConsoleKey.Backspace)
{
//Console.Write(cki.KeyChar);
if (data.Length >= 1)
{
data = data.Remove(data.Length - 1);//最後の一文字を消す
}
}
else if (cki.Key == ConsoleKey.Enter)
{
break;//入力を抜ける
}
else if (cki.Key == ConsoleKey.Delete ||
cki.Key == ConsoleKey.LeftArrow ||
cki.Key == ConsoleKey.RightArrow){
//無視する(もっと無視すべきキーはたくさんあると思います。m(_ _)m)
continue;
}
else
{//特殊キー以外(あるいは、特定キーのみにするとか…)
data = data + cki.KeyChar;//文字列に追加する。
}

//現在のデータを表示(小細工有)
Console.SetCursorPosition(cl, ct);
Console.Write(data+" ");//Backspace押された時用に余分にスペース出力
//余分なスペース出力分、カーソルをバック
Console.SetCursorPosition(Console.CursorLeft - 2, Console.CursorTop);
}

//現在のデータを表示
Console.SetCursorPosition(cl, ct);
Console.WriteLine(data);

return data;
}

static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
//Thread thread = new Thread(new ThreadStart(ReadLine));
//thread.IsBackground = true;
//thread.Start();

Console.Write("1 + 1 = ");

long startTime = DateTime.Now.Ticks;
input = "";

//5秒経過するか入力が有るまで待つ

input = MyReadLine(5);//■タイムアウト・エミュレート

//while (startTime + 50000000 > DateTime.Now.Ticks && input == "") { }
//thread.Abort();
//thread.Interrupt();

if (input == "2")
{
Console.WriteLine("○");
}
else
{
Console.WriteLine("×");
}

Thread.Sleep(500);
}

}
}
}

//以上です。

質問した人からのコメント

2012/5/4 21:44:00

降参 もっと単純なものだと思っていたら実は結構大変なんですね。
ありがとうございました

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問や知恵ノートは選択されたID/ニックネームのMy知恵袋で確認できます。