C#での動的スレッド対応コードのサンプル

立ち上げるスレッド数を動的に管理して
マルチスレッド処理をやるサンプルを書いてみましたです

コンストラクタ引数に0とかマイナスの値を指定したら
稼動しているPCのCPUコア数を認識して
コア数と同じスレッドを立ち上げます

正の数を指定したら,その数だけ,スレッドを立ち上げます

スレッド処理の本体は

ThreadClassJobCore.ThreadLoop()

に記述してくださいませ

とりあえず,軽くテストはしましたが
バグってたら,スマソってことで :mrgreen:


画像処理とか,大量のデータを同じ処理かけるときに威力を発揮するはずですわん 😉


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;

//Copyright(c) 2008-  bMount Products
//
namespace bMountLibrary
{
  public class ThreadClassCtrl : IDisposable
  {
    #region API
        [DllImport("kernel32")]
        static extern void GetSystemInfo(ref SYSTEM_INFO ptmpsi); 
 
        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEM_INFO {
            public uint dwOemId;
            public uint dwPageSize;
            public uint lpMinimumApplicationAddress;
            public uint lpMaximumApplicationAddress;
            public uint dwActiveProcessorMask;
            public uint dwNumberOfProcessors;
            public uint dwProcessorType;
            public uint dwAllocationGranularity;
            public uint dwProcessorLevel;
            public uint dwProcessorRevision;
        }
    #endregion

    #region イベント
    public delegate void OnCorrelationThreadJobFix (object o, ThreadJobFixArg e);
    public delegate void OnCorrelationThreadLoopEnd(object o, ThreadLoopEndArg e);
    public event OnCorrelationThreadJobFix    OnThreadJobFixEvent;    //スレッド処理中向けイベント
    public event OnCorrelationThreadLoopEnd    OnThreadLoopEndEvent;    //スレッドループアウト伝達向けイベント
    #endregion

    #region 変数
    #region スレッド関連
    private int        m_ThreadCount;        //スレッド数

    private bool          m_ThreadOnFL;        //スレッドループを生かしている間はTrue
    private bool[]          m_ThreadJobFL;        //スレッド処理を開始する場合はTrue
    private Thread[]        m_Thread;          //スレッドクラス
    private ThreadClassJobCore[]  m_ThreadJobMain;      //スレッドの処理本体を記述するクラス

    #endregion

    private bool m_disposed = false;
    #endregion

    //コンストラクタ
    //
    //コンストラクタ引数 tmpThreadCount <= 0 の場合
    //実行環境PCのコア数と同じスレッドを立ち上げる
    public ThreadClassCtrl(int tmpThreadCount)
    {
      #region
      m_ThreadCount = (tmpThreadCount <= 0) ? GetCPUCoreCount() : tmpThreadCount;

      m_ThreadOnFL        = true;
      m_ThreadJobFL    = new bool[m_ThreadCount];
      m_Thread      = new Thread[m_ThreadCount];
      m_ThreadJobMain     = new ThreadClassJobCore[m_ThreadCount];

      for(int i = 0; i < m_ThreadCount; i++)
      {
        m_ThreadJobFL[i] = false;

        m_ThreadJobMain[i] = new ThreadClassJobCore(this, i);

        m_Thread[i] = new Thread(new ThreadStart(m_ThreadJobMain[i].ThreadLoop));

        m_Thread[i].Name = "スレッド:" + i.ToString();
        m_Thread[i].Start();

        Debug.WriteLine(m_Thread[i].Name + " スタート");
      }
      #endregion
    }

    //デストラクタ
    ~ThreadClassCtrl()
    {
      #region
      DisposeCore();
      #endregion
    }

    //リソースの解放
    public void Dispose()
    {
      #region
      DisposeCore();
      #endregion
    }

    //リソースの解放
    private void DisposeCore()
    {
      #region

      if(m_disposed == false)
      {
        m_ThreadOnFL = false;
        for(int i = 0; i <200; i++)  //スレッドが死ぬまで最大200ミリ秒待たしてみる
        {
          bool fl = true;
          for(int j = 0; j < m_ThreadCount; j++)
          {
            if (m_Thread[j] != null)
            {
              fl = false;
              break;
            }
          }

          if (fl == true)
          {
            break;
          }

          Application.DoEvents();
          Thread.Sleep(1);
        }
      }
      m_disposed = true;
      #endregion
    }

    //---------------------------------------------
    //処理の開始
    //
    //---------------------------------------------
    public void Start()
    {
      #region

      for(int i = 0; i < m_ThreadCount; i++)
      {
        m_ThreadJobFL[i] = true;
      }

      #endregion
    }

    //---------------------------------------------
    //処理の停止
    //
    //---------------------------------------------
    public void Stop()
    {
      #region
      #endregion
    }

    //---------------------------------------------
    //CPUコア数を取得
    //
    //---------------------------------------------
    private int GetCPUCoreCount()
    {
      #region

      SYSTEM_INFO sysInfo = new SYSTEM_INFO();
      GetSystemInfo(ref sysInfo);

      return (int) sysInfo.dwNumberOfProcessors;
      #endregion
    }

    #region スレッド主処理クラス
    internal class ThreadClassJobCore
    {
      private ThreadClassCtrl m_MainClass;
      private int m_ThreadNo;

      //---------------------------------------------
      //コンストラクタ
      //
      //---------------------------------------------
      public ThreadClassJobCore(ThreadClassCtrl tmpParent, int tmpNo)
      {
        #region
        m_MainClass = tmpParent;
        m_ThreadNo  = tmpNo;
        #endregion
      }

      //---------------------------------------------
      //スレッドループ
      //
      //---------------------------------------------
      public void ThreadLoop()
      {
        #region
        while (m_MainClass.m_ThreadOnFL == true)
        {
          if (m_MainClass.m_ThreadJobFL[m_ThreadNo] == false)    //フラグがfalse時は待機させる
          {
              Thread.Sleep(1);
              continue;
          }

          //ここいらに処理を記述
          

          if (m_MainClass.OnThreadJobFixEvent != null)
          {
            m_MainClass.OnThreadJobFixEvent(m_MainClass, new ThreadJobFixArg(ThreadJobFixArg.JobFixMode.Mode1, m_ThreadNo, 0, 10));  //適時変えてください
          }

          m_MainClass.m_ThreadJobFL[m_ThreadNo] = false;   //処理が終わったら待機動作へもどす
          
        }

        if (m_MainClass.OnThreadLoopEndEvent != null)     //スレッドループを抜けたら,イベントを飛ばす
        {
            m_MainClass.OnThreadLoopEndEvent(m_MainClass, new ThreadLoopEndArg(m_ThreadNo));
        }

        Debug.WriteLine(m_MainClass.m_Thread[m_ThreadNo].Name + " 終了");

        m_MainClass.m_Thread[m_ThreadNo] = null;
        #endregion
      }

    }
    #endregion

    #region イベント引数クラス
    public class ThreadJobFixArg : EventArgs
    {
      public enum JobFixMode {Mode1, Mode2}

      private JobFixMode m_Mode;
      private int  m_ThreadNo;
      private int  m_FixCount;
      private int  m_MaxJobCount;

      public JobFixMode Mode { get { return m_Mode;} set { m_Mode = value;}}
      public int ThreadNo { get { return m_ThreadNo;} set { m_ThreadNo = value;}}
      public int FixCount { get { return m_FixCount;} set { m_FixCount = value;}}
      public int MaxJobCount { get { return m_MaxJobCount;} set { m_MaxJobCount = value;}}

      public ThreadJobFixArg(JobFixMode m, int tmpNo, int tmpFixCount, int tmpMaxJobCount)
      {
        m_Mode        = m;
        m_ThreadNo    = tmpNo;
        m_FixCount    = tmpFixCount;
        m_MaxJobCount = tmpMaxJobCount;
      }
    }

    public class ThreadLoopEndArg : EventArgs
    {
      private int  m_ThreadNo;
      public int ThreadNo { get { return m_ThreadNo;}}
      
      public ThreadLoopEndArg(int tmpNo){ m_ThreadNo = tmpNo;}
    }
    #endregion
  }
}