レガシーコードからの脱却

レガシーな職場でも独学でどうにか頑張っていくブログです。

【お勉強記録】C#文法学び直し。並列処理1

並列処理

仕事では業務アプリを主に担当しているのですが、仕事上で並列処理を使われているのを実はほとんど見ません。 (実行ボタンを押してから、処理完了まで30分以上かかかるものも多々あるのに…その間はプログラムはフリーズ状態です…)

並列処理、マルチスレッド…いまいちきちんと理解できていなかったので、お勉強です。

Threadクラス

処理側

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace ThreadTest
{
    class Counter
    {
        public string Caption { get; set; }
        public int Count { get; set; }

        public Counter(string caption, int count)
        {
            this.Caption = caption;
            this.Count = count;
        }

        public void Play()
        {
            int count = 0;
            while (count < this.Count)
            {
                count++;
                Console.WriteLine("{0}({1}回目)", this.Caption, count.ToString());
                Thread.Sleep(200);
            }
        }

        //スレッドクラスのためのメソッド
        public void ThreadPlay()
        {
            ThreadStart threadStart = new ThreadStart(this.Play);
            Thread thread = new Thread(threadStart);
            thread.Start();
        }
    }
}

実行側

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadTest
{
    class Program
    {
        static void Main(string[] args)
        {            
            new Counter("サブスレッド", 5).ThreadPlay();
            new Counter("メインスレッド", 3).Play();            
            Console.ReadLine();
        }
    }
}

実行するとそれぞれ独立して処理が行われているのがわかります。

ThreadStartデリゲートに処理を登録して、新たなスレッドを作成してそこにデリゲートをわたすような感じでしょうか。

ちなみに同期はlockステートメントで実現するそうです。

先ほどのをすこし書き換えます。

        //スレッドクラスのためのメソッド
        public void ThreadPlay(object obj)
        {
            ParameterizedThreadStart threadStart = new ParameterizedThreadStart(this.WaitPlay);
            Thread thread = new Thread(threadStart);
            thread.Start(obj);
        }

        public void WaitPlay(object obj)
        {
            if (obj != null)
            {
                lock (obj) { this.Play(); }
            }
            else
            {
                this.Play();
            }
        }

lockステートメントを使うためWaitPlayメソッドとパラメータを使うためにThreadStartクラスをParameterizedThreadStartに変更しています。

       static void Main(string[] args)
        {
            object obj = new object();

            new Counter("サブスレッド", 5).ThreadPlay(obj);
            new Counter("メインスレッド", 2).Play();
            lock (obj) { new Counter("同期確認", 3).Play(); }
            Console.ReadLine();
        }

f:id:Gappory:20170812170019p:plain

きちんとサブスレッドが終了するのを待ってから、次の処理が行われたようです。

調べているとこのThreadクラスは様々な理由でいまいちなようで、いまはTaskクラスを使うべきだそうです。

ThreadじゃなくTaskを使おうか? - Qiita

なので、この次はTaskを自習します。