Threadのメッセージポンプ

C#のSystem.Threading.Threadはなかなかいいもんで。
ワーカスレッドならより簡単なのだが、常駐スレッドってのも業務系では良く使う。
で、ワーカスレッドにメッセージポンプを持たせるとするとこんな。
-- ThreadQueue.cs --
using System;
using System.Collections.Generic;
using System.Threading;

namespace MyThread
{
public class ThreadQueue
{
private List<object> queue_;
private ManualResetEvent mrevent_;
public int Count {
get { return queue_.Count; }
}
public ThreadQueue ()
{
queue_ = new List<object>();
mrevent_ = new ManualResetEvent(false);
}
public void Add(object o)
{
lock(this) {
queue_.Add (o);
mrevent_.Set ();
}
}
public object Get()
{
if (queue_.Count == 0) {
mrevent_.WaitOne ();
}
return getMsg ();
}
private object getMsg()
{
object o = null;
lock(this) {
if (queue_.Count > 0) {
o = queue_[0];
queue_.RemoveAt (0);
mrevent_.Reset ();
}
}
return o;
}
}
}
メッセージが何も無い時は、GetはManualResetEventでブロックして待つことにする。
-- ThreadObject.cs --
using System;
using System.Collections.Generic;
using System.Threading;

namespace MyThread
{
public class ThreadObject
{
private string id_;
private Thread thread_;
private MyThread.ThreadQueue queue_;
public ThreadObject (int n)
{
queue_ = new MyThread.ThreadQueue();
thread_ = new Thread(this.DoWork);
thread_.Start (n.ToString ());
}
public void Send(object o)
{
queue_.Add (o);
}

private void DoWork(object o)
{
id_ = (string)o;
object msg;
while ((msg = queue_.Get()) != null) {
System.Console.WriteLine (id_
+ ":" + ((int)msg).ToString ()
+ " ::(" + queue_.Count.ToString () + ")");
Thread.Sleep (int.Parse (id_) * 200);
}
System.Console.WriteLine (id_ + ":End");
}
}
}
ThreadQueueを抱えてワーカスレッドを起こすThreadObject。
DoWorkの中のwhileがメッセージポンプになる。
キューの溜まり具合を確認するためにSleepを入れてある。
実際にはThreadQueueに格納するのは、業務的なobjectになるだろう。
で、これを動かしてみる。
-- Main.cs --
using System;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace MyThread
{
class MainClass
{
public static void Main (string[] args)
{
Parallel.For (0, 3, i => {
var th = new MyThread.ThreadObject(i);
for (int j = 1; j < 10; j++) {
th.Send (j);
}
th.Send(null);
});
}
}
}

で実行すると、それらしく動く。
-- 実行結果 --
1:1 ::(9)
0:1 ::(9)
2:1 ::(9)
0:2 ::(8)
0:3 ::(7)
0:4 ::(6)
0:5 ::(5)
0:6 ::(4)
0:7 ::(3)
0:8 ::(2)
0:9 ::(1)
0:End
1:2 ::(8)
1:3 ::(7)
2:2 ::(8)
1:4 ::(6)
2:3 ::(7)
1:5 ::(5)
1:6 ::(4)
2:4 ::(6)
1:7 ::(3)
1:8 ::(2)
2:5 ::(5)
1:9 ::(1)
1:End
2:6 ::(4)
2:7 ::(3)
2:8 ::(2)
2:9 ::(1)
2:End

Press any key to continue...

まー、Linuxのmonoでも、Windowsの.NETでもそれらしく動く。
実際の業務ではThreadObjectを管理するクラスで、複数常駐スレッドを動かしちゃう、みたいなことをする。
Cでプロセスたくさん作って、セマフォであれこれ同期したり、共有メモリ使ったりするよりもC#は断然楽ではある。
スポンサーサイト

コメントの投稿

非公開コメント

プロフィール

f_yamaki

Author:f_yamaki

アクセスカウンタ
最近の記事
最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
ブロとも申請フォーム

この人とブロともになる

ブログ内検索
RSSフィード
リンク