2011-03-11 18 views
3

私は単純なC#グラフィックスライブラリをマルチスレッド化しようとしています。しかし、このコードの導入後:マルチスレッドコードの頻繁なラグスパイク

/* foreach (IAffector affector in affectorLookup.Values) 
    affector.Update(timestep); */ 

taskManager.Value = timestep; taskManager.Start(); 

foreach (IAffector affector in affectorLookup.Values) 
    taskManager.AddToQueue(affector.Update); 
taskManager.StopWhenDone(); 
taskManager.Wait(); 

シミュレーションは、(以前のコードを追加することが私のコードになりますので、私は、確かに言うことはできませんTaskHandler.Runに起因すると思われる鋭いラグスパイクを、経験して開始しますプロファイラはTaskHandler.Run以外のものは無視します)。

タスクマネージャ:

public class TaskManager 
{ 
    public delegate void MethodDel(float timestep); 
    private Queue<MethodDel> queue; 
    private List<TaskHandler> handlers; 
    private float value; 


    public float Value 
    { 
     get 
     { 
      return value; 
     } 
     set 
     { 
      this.value = value; 
     } 
    } 


    public TaskManager() 
    { 
     this.queue = new Queue<MethodDel>(); 
     this.handlers = new List<TaskHandler>(System.Environment.ProcessorCount); 

     for (int t = 0; t < this.handlers.Capacity; ++t) 
      this.handlers.Add(new TaskHandler(this)); 

     this.value = 0; 
    } 


    public void Start() 
    { 
     foreach (var handler in handlers) 
      handler.Start(); 
    } 


    public void Stop() 
    { 
     lock (queue) 
      queue.Clear(); 

     foreach (var handler in handlers) 
      handler.StopWhenDone(); 
    } 


    public void StopWhenDone() 
    { 
     foreach (var handler in handlers) 
      handler.StopWhenDone(); 
    } 


    public void AddToQueue(MethodDel method) 
    { 
     lock (queue) 
      queue.Enqueue(method); 
    } 


    public bool GetFromQueue(out MethodDel method) 
    { 
     lock (queue) 
     { 
      if (queue.Count == 0) { method = null; return false; } 

      method = queue.Dequeue(); 
      return true; 
     } 
    } 


    public int GetQueueCount() 
    { 
     return queue.Count; 
    } 

    internal void Wait() 
    { 
     // Have to wait for them one at a time because the main thread is STA. 

     WaitHandle[] waitHandles = new WaitHandle[1]; 
     // for (int t = 0; t < handlers.Count; ++t) 
      // waitHandles[t] = handlers[t].WaitHandle; 

     // WaitHandle.WaitAll(waitHandles); 
     for (int t = 0; t < handlers.Count; ++t) 
     { waitHandles[0] = handlers[t].WaitHandle; WaitHandle.WaitAll(waitHandles); } 
    } 
} 

とタスクハンドラ:

public class TaskHandler 
{ 
    private TaskManager manager; 
    private Thread thread; 
    private bool stopWhenDone; 
    private ManualResetEvent waitHandle; 


    public ManualResetEvent WaitHandle 
    { 
     get 
     { 
      return waitHandle; 
     } 
    } 


    public TaskHandler(TaskManager manager) 
    { 
     this.manager = manager; 
    } 


    public void Start() 
    { 
     waitHandle = new ManualResetEvent(false); 

     stopWhenDone = false; 

     thread = new Thread(Run); 
     thread.IsBackground = true; 
     thread.SetApartmentState(ApartmentState.MTA); 
     thread.Start(); 
    } 


    public void StopWhenDone() 
    { 
     this.stopWhenDone = true; 
    } 

    // Possible source of slowdown 
    private void Run() 
    { 
     TaskManager.MethodDel curMethod; 
     while (!stopWhenDone || manager.GetQueueCount() > 0) 
     { 
      if (manager.GetFromQueue(out curMethod)) 
      { 
       curMethod(manager.Value); 
      } 
     } 
     waitHandle.Set(); 
    } 
} 

答えて

3

スレッドを起動するには、重い操作です。あなたが経験しているほど重いかどうかは分かりませんが、それはそうかもしれません。また、すべての処理を並行して実行すると、システムに大きな負担をかける可能性があります。

+0

私はデュアルコアを持っているので、いくつかの利点を期待するのは不合理だとは思わないでしょう。私はスレッドの開始時間、おかげでテストします。 –

+0

これで面白いです。デバッグまたはリリースでは、毎秒100,000の新しいスレッドオブジェクトを作成できます。ただし、Thread.Startはデバッグでは1秒間に100回、リリースでは1秒間に2,700回しか実行できません。 –

+0

スレッドの開始には400kサイクルのコストがかかりますが、新しいスレッドを作成するだけで新しいスタックを割り当てることになります。個人的には、コアと同じ数のスレッドだけを作成し、各スレッドはキューで噛み砕くようなデザインに見えます。 – Bengie

0

私は、スパイクがwaitHandle.Set()と関係があることを確かめます。

私は全体的なデザインが好きですが、以前はWaitHandleを使用していませんでしたので、これがデザインとどのように相互作用するかはわかりません。

関連する問題