C〓〓〓〓マルチスレッド学習の(四)スレッド池を使ってマルチスレッドの自動管理を行います.

5759 ワード

本論文の実例は、C〓〓〓マルチスレッド学習のためのスレッド池を用いたマルチスレッドの自動管理について述べる.皆さんの参考にしてください.具体的には以下の通りです
マルチスレッドのプログラムには、しばしば2つのケースがあります.
一つの場合:   アプリケーションでは、スレッドは大部分の時間を待ち状態にして、あるイベントが発生するのを待って、それに応答するために、通常はThreadPool(スレッド池)を使って解決します.
もう一つの場合:スレッドは通常休止状態にあるが、周期的に起動されるだけで、これは一般的にTimer(タイマー)を使用して解決される.
ThreadPoolクラスは、Windows 2000以上のシステムサポートを必要とするシステムによって維持されているスレッドプール(スレッドと見なされてもよいコンテナ)を提供しています.これらのいくつかの方法は、高いバージョンのWindowsならではのAPI関数を呼び出すためです.
スレッドをオンラインプログラムにセットするには、ThreadPool.QueueUser WorkItem()の方法が必要です.この方法の原型は以下の通りです.
WaitCallbackプロキシの代表的な関数を呼び出すスレッドをスレッドに入れます.

public static bool QueueUserWorkItem(WaitCallback);
 
リロードの方法は、パラメータobjectがWaitCallbackに代表される方法に伝達されます.

public static bool QueueUserWorkItem(WaitCallback, object);
注意:
ThreadPoolクラスは静的なクラスであり、オブジェクトを生成する必要もない.また、この方法を使用すると、オンラインプログラムにアイテムが追加されますので、このアイテムはキャンセルできません.
ここでは自分でスレッドを作る必要はありません.あなたがやりたい仕事を関数として書いて、パラメータとしてThreadPool.QueueUserWorkItemに渡すだけでいいです.伝達の方法はWaitCallbackのエージェントに依存します.スレッドの建立、管理、運行などはシステムによって自動的に完成されます.それらの複雑な細かい問題を考慮する必要はありません.
ThreadPoolの使い方:
まずプログラムは、信号のようなオブジェクトを作成し、他のスレッドに信号を送ることができます.この例では、スレッドプール内のスレッドの動作がすべて完了すると、Manual ReseetEventオブジェクトは信号があるように設定され、メインスレッドの運転継続を通知します.
Manual ReseetEventオブジェクトにはいくつかの重要な方法があります.
このオブジェクトを初期化すると、ユーザはそのデフォルトの状態を指定することができます.初期化後、オブジェクトは元の状態を維持し、Reset()またはSet()メソッドが呼び出されるまでは、
Reset()メソッド:無信号状態に設定します.Set()メソッド:信号状態に設定します.WaitOne()メソッド:Manual ReseetEventオブジェクトが信号状態になるまで現在のスレッドをオンにします.このスレッドはアクティブになります.そして、プログラムは、自動的に確立されたスレッドを初期化するために、関数として提供される作業項目をスレッド池に追加する.すべてのスレッドが実行された後、Manual Resite Event.Set()メソッドが呼び出されました.Manual Resite Event.WaitOne()メソッドを呼び出して待機状態のメインスレッドがこの信号を受信し、その後、実行して、後の作業を完了します.
ThreadPoolの使い方例:

using System;
using System.Collections;
using System.Threading;
namespace ThreadExample
{
 //             ,        
 public class SomeState
 {
 public int Cookie;
 public SomeState(int iCookie)
 {
  Cookie = iCookie;
 }
 }

 public class Alpha
 {
public Hashtable HashCount;
public ManualResetEvent eventX;
public static int iCount = 0;
public static int iMaxCount = 0;

  public Alpha(int MaxCount) 
{
  HashCount = new Hashtable(MaxCount);
  iMaxCount = MaxCount;
}

//          Beta()  
public void Beta(Object state)
{
 //       hash    Cookie  
  Console.WriteLine(" {0} {1} :", Thread.CurrentThread.GetHashCode(),((SomeState)state).Cookie);
  Console.WriteLine("HashCount.Count=={0}, Thread.CurrentThread.GetHashCode()=={1}", HashCount.Count, Thread.CurrentThread.GetHashCode());
  lock (HashCount) 
  {
 //     Hash         Hash ,    
 if (!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode()))
   HashCount.Add (Thread.CurrentThread.GetHashCode(), 0);
  HashCount[Thread.CurrentThread.GetHashCode()] = 
   ((int)HashCount[Thread.CurrentThread.GetHashCode()])+1;
 }
   int iX = 2000;
   Thread.Sleep(iX);
   //Interlocked.Increment()         ,        
   Interlocked.Increment(ref iCount);

   if (iCount == iMaxCount)
   {
  Console.WriteLine();
 Console.WriteLine("Setting eventX ");
 eventX.Set();
  }
 }
 }
  public class SimplePool
  {
   public static int Main(string[] args)
   {
    Console.WriteLine("Thread Pool Sample:");
    bool W2K = false;
    int MaxCount = 10;//          10   
    //  ManualResetEvent             
    ManualResetEvent eventX = new ManualResetEvent(false);
    Console.WriteLine("Queuing {0} items to Thread Pool", MaxCount);
    Alpha oAlpha = new Alpha(MaxCount); 
    //     
    //     oAlpha   eventX  
    oAlpha.eventX = eventX;
    Console.WriteLine("Queue to Thread Pool 0");
    try
    {
     //          
     //     Windows 2000       API,      NotSupportException  
     ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta), new SomeState(0));
     W2K = true;
    }
    catch (NotSupportedException)
    {
     Console.WriteLine("These API's may fail when called on a non-Windows 2000 system.");
     W2K = false;
    }
    if (W2K)//        ThreadPool   .
    {
     for (int iItem=1;iItem < MaxCount;iItem++)
     {
      //      
      Console.WriteLine("Queue to Thread Pool {0}", iItem);
      ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta), new SomeState(iItem));
     }
     Console.WriteLine("Waiting for Thread Pool to drain");
     //       ,     ManualResetEvent.Set()  
     eventX.WaitOne(Timeout.Infinite,true);
     //WaitOne()             eventX.Set()     
     Console.WriteLine("Thread Pool has been drained (Event fired)");
     Console.WriteLine();
     Console.WriteLine("Load across threads");
     foreach(object o in oAlpha.HashCount.Keys)
      Console.WriteLine("{0} {1}", o, oAlpha.HashCount[o]);
    }
    Console.ReadLine();
    return 0;
   }
  }
 }
}

プログラムで注意すべき点:SomeStateクラスは情報を保存するデータ構造であり、プログラムではパラメータとしてスレッドごとに渡されています.有用な情報をパッケージ化してスレッドに提供する必要があるので、このような方法は非常に効果的です.プログラムで発生したInterLocked類もマルチスレッドプログラムのために専用に存在しており、いくつかの有用な原子操作を提供している.
原子操作:マルチスレッドプログラムにおいて、このスレッドがこの動作を起動して変数を修正すると、他のスレッドはこの変数を修正できなくなります.これはロックキーと本質的に同じです.
上のプログラムを徹底的に分析して、スレッド池の本質を把握し、その存在意義を理解してこそ、それを適切に使うことができる.
ここで述べたように、皆さんのC〓プログラムの設計に役に立ちます.