C#でマルチスレッドプログラミング−1

C#でマルチスレッドプログラムを書くには色々方法があるようなので、がんばって勉強しつつ、その結果をメモメモと。
この記事によると

  1. スレッド(Thread)
  2. スレッドプール(ThreadPool)
  3. デリゲート(BeginInvoke)
  4. タイマー(Timer)

という分類になるらしい。ただこの記事は古いので今だとParallel.Forみたいなことができるよになっているのだとかなんとか。

Threadクラス

まずは一番基本となるThreadクラスを使ってみる。要はスレッドクラスにマルチスレッドで走らせたい関数をThreadStartデリゲートとして突っ込んで実行するということらしい。メインスレッドが終わるまで待つにはJoinメソッドを使えばよろしぞっと。

using System;
using System.Threading;

class Program
{
    //別スレッドとして実行される関数
    static void ThreadProcess()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Thread Process : {0}", i);
            //0.1秒待つ
            Thread.Sleep(100);
        }
    }
    static void Main(string[] args)
    {
        Console.WriteLine("Main Thread Start");

        //スレッドクラスのオブジェクトを生成。
        //コンストラクタの引数として上で作成した関数をThreadStartデリゲートとして突っ込んでおく。
        Thread thr = new Thread(new ThreadStart(ThreadProcess));

        //別スレッド開始
        thr.Start();
        //適当なメインスレッドでの処理
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Main thread {0}", i);
            //0.05秒待つ
            Thread.Sleep(50);
        }

        //thrが終わるまでMainスレッドを止める。
        //これがないと次の「End !!」が画面に表示される
        thr.Join();
        Console.WriteLine("End !!");
    }
}

実行結果は

Main Thread Start
Main thread 0
Thread Process : 0
Main thread 1
Thread Process : 1
Main thread 2
Main thread 3
Thread Process : 2
Main thread 4
Main thread 5
Thread Process : 3
Main thread 6
Main thread 7
Thread Process : 4
Main thread 8
Main thread 9
Thread Process : 5
Thread Process : 6
Thread Process : 7
Thread Process : 8
Thread Process : 9
End !!

となる。thr.Join()をコメントアウトして実行するとthrのタスク終了を待たないで「End !!」の表記が実行されちゃう。

ThreadPoolクラス

別スレッドで走らせたいタスクをWaitCallBackデリゲートとしてキューに突っ込んでおくと、それらを順次実行してくれる。
各スレッドごとに1つだけ引数をobject型として渡すことができる。

using System;
using System.Threading;

class Program
{
    //別スレッドとして実行される関数
    static void ThreadProcess(object state)
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Thread Process {0}: {1}", state.ToString(), i);
            //0.1秒待つ
            Thread.Sleep(100);
        }
    }
    static void Main(string[] args)
    {
        Console.WriteLine("Main Thread Start");
        //別スレッドで実行したいものをWaitCallbackデリゲートとして生成
        WaitCallback x = new WaitCallback(ThreadProcess);
        //キューに突っ込んでおくと、別スレッドで事項してくれる。
        //引数を1つ、object型の変数として渡せるのでそれを使って2つのスレッドを区別した。
        ThreadPool.QueueUserWorkItem(x, "A");
        ThreadPool.QueueUserWorkItem(x, "B");
        
        //なんかの処理の代替としてメインスレッドを強制的に止めておく
        //これがコメントアウトされると別スレッドで上記タスクが実行されない
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }
}

実行結果は

Main Thread Start
Thread Process A: 0
Thread Process B: 0
Thread Process A: 1
Thread Process B: 1
Thread Process A: 2
Thread Process B: 2
Thread Process A: 3
Thread Process B: 3
Thread Process A: 4
Thread Process B: 4
Thread Process A: 5
Thread Process B: 5
Thread Process A: 6
Thread Process B: 6
Thread Process A: 7
Thread Process B: 7
Thread Process A: 8
Thread Process B: 8
Thread Process A: 9
Thread Process B: 9
Main thread exits.

参考LINKのThreadPool クラス (System.Threading)

メモ
マネージ スレッド プールのスレッドは、バックグラウンド スレッドです。 つまり、これらのスレッドの IsBackground プロパティは true です。 したがって、ThreadPool のスレッドは、すべてのフォアグラウンド スレッドが終了した後は、アプリケーションの実行状態を維持しません。

という記載があるように、すべてのスレッドはバックグラウンドで走る点に注意。つまりメインスレッドが終了すると別スレッドで走らせている処理がおわらなくてもアプリケーションが終了してしまう。