マルチスレッド

とりあえず実験です。

C# のマルチスレッドは何種類か実現方法があるのですが、一番簡単なスレッドプールを使ってみます。

private static object lockObject = new Object();

private static void threadMethod(object o)
{
    // 非同期で実行される部分

    lock(lockObject)
    {
        // lock による排他処理
    }
}

private void button1_Click(object sender, EventArgs e)
{
    WaitCallback wcb = new WaitCallback(threadMethod);
    ThreadPool.QueueUserWorkItem(wcb);
}

細かい動作の原理は良く分かりませんが、とりあえずこんな感じです。

んで、lock によって lockObject のロックを取得するのですが、これは lockObject へのアクセスを出来なくなるのでは無く、他のスレッドでロックが取得出来ないようにする為の仕組みです。結局人間が処理を把握しておかないと駄目なんですね。当たり前ですが、重要なポイントです。Delphi の Synchronized はメインスレッドで動作させる為の仕組みなので、この辺りの考え方が異なります。どっちが良いという話では全く無いですが。

でも、結構手軽に扱えますね〜。同期を取るのはそれなりに面倒ですが、別にクラスを作る必要が無いってのはポイント高いですね。

ループ処理には DoEvents()

C#に限った話ではないですが。

ループ処理を行うと、その間ウィンドウの操作等を全く受け付けなくなります。例えばあるディレクトリの配下にあるファイルの一覧を取得するプログラムを書いた時、場合によってはかなり深い階層を辿って一覧を作ったりますよね。この場合、ループ処理がなかなか終わらないのでそのあいだ他の処理が全く出来なくなります*1

これを避ける為に Application.DoEvents() をループ処理の中に入れてやる訳です。この DoEvents() はウィンドウの操作等のメッセージがキューに溜まってればそちらを処理しろ、という命令です。しかし、キューにメッセージが溜まりまくってたら、もとのループ処理に戻って来るまでかなり時間が掛かったりします。逆に DoEvents() から DoEvents() までの間の処理時間が長いと、その間のウィンドウの操作等が思ったように出来なくなったりします。出来ないよりは全然マシではありますが。

うまく使えば応答速度をそれなりにすることが出来るので、マルチスレッド化する前にまず DoEvents() で出来ないかを検討することが必要です*2。どうしても DoEvents() では無理ということになれば、その時改めてスレッドを分ければ良いのですから。

*1:他のプロセスは動きます

*2:同一プロセスの別スレッドはそれなりに負担になるらしい