2006-03-16

λ プログラミング環境

一からある程度まで組み上げるようなプログラミング作業は平日の昼間にはとてもできない。

λ [.NET] producer スレッドと consumer スレッドを同期する

非同期読み出しをProducer, 非同期書き込みをConsumer として実装した後以下のような 片方向中継器 クラスを作った。

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;

namespace ProxyConnections
{
    public class 片方向中継器
    {
        /// <summary>
        /// 終了時に子スレッドを待機する時間。ミリ秒単位
        /// </summary>
        private int 終了待機時間ms = 10000;
        private 非同期読み出し _リーダー;
        private 非同期書き込み _ライター;
        private Queue<MemoryStream> _キュー = new Queue<MemoryStream>();
        private 同期用イベント _同期用イベント = new 同期用イベント();
        private Thread _リーダーThread;
        private Thread _ライターThread;

        /// <summary>
        /// コンストラクター
        /// </summary>
        /// <param name="i">オープン済みの入力ストリーム</param>
        /// <param name="o">オープン済みの出力ストリーム</param>
        public 片方向中継器(Stream i, Stream o)
        {
            _リーダー = new 非同期読み出し(_キュー, _同期用イベント, i);
            _ライター = new 非同期書き込み(_キュー, _同期用イベント, o);
            _リーダーThread = new Thread(_リーダー.スレッド実行);
            _ライターThread = new Thread(_ライター.スレッド実行);
        }

        /// <summary>
        /// 処理を開始する(内部的にはスレッドの開始)
        /// </summary>
        public void 開始()
        {
            // TODO: スレッドの終了時にイベントを発生させて後始末が可能なようにする
            _リーダーThread.Start();
            _ライターThread.Start();
        }

        /// <summary>
        /// 処理を終了させる。(内部的にはスレッドの終了)
        /// コンストラクターに渡したストリームの Close 処理等はしていない
        /// </summary>
        public void 終了()
        {
            _同期用イベント.終了イベント.Set();
            _リーダーThread.Join(終了待機時間ms);
            if (_リーダーThread.IsAlive) { _リーダーThread.Abort(); }
            _ライターThread.Join(終了待機時間ms);
            if (_ライターThread.IsAlive) { _ライターThread.Abort(); }
        }
    }
}

それから片方向中継器クラスを二つ束ねた両方向中継器クラスを作成。 TCPListerとTCPClientを使ったストリームを渡したら、一応パケット中継プログラムとして動くようになってしまった。

あとは後始末用のイベントを組み込めば原型は完了になりそう。それ以外にも適当なチェックポイントにイベントを組み込むと。 20世紀のネットワークプログラミングを思い出すと、あまりの楽さ加減に涙が出る。

ただ、Queue<MemoryStream> だと、キューにつっこむMemoryStreamが使い捨てになるので、 効率を追求する場面になったらリングバッファに置き換えたいところ。 それさえ単体テストが充実していれば、へろっとリファクタリングじゃよー。楽すぎる。

今回はいまいちいい日本語が浮かばなかった識別子多数。

[]