C#:Eventは溜まるのか、溜まらないのか
和魂で動画ダウンロードがうまくいかない。
HTTPのダウンロード処理はスレッドを起こしてイベントによりダウンロードを実行するようにしているのだが、どうやらイベントの使い方を勘違いしているために問題が発生しているみたいなのだ。
イベントを発火させたら、それは受け取られるまで溜まったまま→イベントを受け付けられる状態に後からなったら溜まっていたものを消化するのか、それともイベントを受け付けられる状態に対してのみイベント発行とともに受け付けられるのか?
つまり、イベントはいつ発生するか?ということなのだが。
んで、プログラムを作って検証してみた。(和魂からピックアップしたので余計なものが入っているかもしれないけど)
こちらはForm1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace testEvent
{
public partial class Form1 : Form
{
private ClassThread th_;
public Form1()
{
InitializeComponent();
th_ = new ClassThread();
th_.startThread();
}
private void button1_Click(object sender, EventArgs e)
{
for (int counter = 0; 10000 > counter; counter++)
{
th_.run();
Application.DoEvents();
}
}
}
}
こちらはスレッドクラス ClassThread.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace testEvent
{
class ClassThread
{
private Thread thread_;
// イベント
// 優先コマンドを実行する(接続処理を行う)
private EventWaitHandle eventWaitCommand_;
// 新しいコマンドの発行
private EventWaitHandle eventNewCommand_;
// スレッドが終了
private EventWaitHandle eventExitLoop_;
private WaitHandle[] eventArray_;
Stopwatch sw_; // 経過時間計測用のタイマ(待機時間の計算のため)
public ClassThread()
{
eventWaitCommand_ = new ManualResetEvent(true); // 初期状態ではコマンドを実行許可にする
eventNewCommand_ = new AutoResetEvent(false);
eventExitLoop_ = new ManualResetEvent(false);
eventArray_ = new WaitHandle[2];
eventArray_[0] = eventNewCommand_;
eventArray_[1] = eventExitLoop_;
sw_ = new Stopwatch();
sw_.Start();
}
// スレッド起動
public void startThread()
{
thread_ = new Thread(this.eventLoop);
thread_.Start();
}
public void run()
{
Trace.WriteLine(String.Format("SET TIME:{0}", sw_.ElapsedMilliseconds));
eventNewCommand_.Set();
}
// スレッドで実行するメソッド
// コマンド通知イベントまたは終了イベントでWaitHandleでの待機解除
// コマンド通知イベントのとき、中の処理を実行。終了イベントのときwhileループを抜ける
private void eventLoop()
{
int eventNo = -1;
// 配列の1つめのEventが発行されたら中の処理を行う。
//(NewCommandならループ、ExitLoopならループ終了)
while (eventNo != 1)
{
eventNo = WaitHandle.WaitAny(eventArray_);
switch (eventNo)
{
case 0: //
// ハンドルが帰ってきたときのみHTTPダウンロードを行う
Trace.WriteLine(String.Format("LOOP TIME:{0} NO:{1}", sw_.ElapsedMilliseconds, eventNo));
Thread.Sleep(1 * 1000); // 1秒待機
break;
}
}
}
}
}
フォームアプリで新規作成してボタンをひとつ貼り付けたもの。
ClassThread::run()を実行すると、イベントを発行してFormに制御をいったん戻す。それをループ。
run()の中でイベントを発行している。そして、スレッドを起こした方はイベント受信待機状態にしておいて、イベントを受信したら1秒待機。
実際に動かしてみると、イベント発生の方は10000回実行するけど、イベント受信の方は1秒ごとに実行して明らかにイベント待機状態の時に発行されたイベントのみ処理している。
よって、イベントは溜まらない。
・・・和魂を直さないと。
« 3D TVを見た | トップページ | 今飲んでいる酒 »
コメント