2011-03-30 60 views
2

我目前正在開發一個必須處理多線程的程序。當我啓動程序時,我運行多個線程(我的示例僅限於一個)。我必須在一個文本框中顯示它們的狀態。我選擇了下一個解決方案。這種方式是正確的嗎?還有其他的模式嗎?也許觀察者?我找不到在網絡上執行此操作的好方法。在C中處理線程狀態的模式#

namespace ThreadTest 
{ 
    public partial class Form1 : Form 
    { 
     // This delegate enables asynchronous calls for setting 
     // the text property on a TextBox control. 
     delegate void ChangedCallback(object sender, JobEventArgs e); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      MyThread myThread = new MyThread(); 
      myThread.Changed += new MyThread.JobEventHandler(myThread_Changed); 

      // Create the thread object, passing in the Alpha.Beta method 
      // via a ThreadStart delegate. This does not start the thread. 
      Thread oThread = new Thread(new ThreadStart(myThread.MyJob)); 

      // Start the thread 
      oThread.Start(); 
     } 

     void myThread_Changed(object sender, JobEventArgs e) 
     { 
      // InvokeRequired required compares the thread ID of the 
      // calling thread to the thread ID of the creating thread. 
      // If these threads are different, it returns true. 
      if (this.textBox1.InvokeRequired) 
      { 
       ChangedCallback d = new ChangedCallback(myThread_Changed); 
       this.Invoke(d, new object[] { sender, e }); 
      } 
      else 
      { 
       // Display the status of my thread 
       textBox1.Text += e.Counter; 
      } 
     } 
    } 

    public class MyThread 
    { 
     // A delegate type for hooking up change notifications. 
     public delegate void JobEventHandler(object sender, JobEventArgs e); 

     // An event that clients can use to be notified whenever the 
     // elements of the list change. 
     public event JobEventHandler Changed; 

     // Invoke the Changed event; called whenever list changes 
     protected virtual void OnChanged(JobEventArgs e) 
     { 
      if (Changed != null) 
       Changed(this, e); 
     } 

     public void MyJob() 
     { 
      for (int i = 0; i < 1000; i++) 
      { 
       Thread.Sleep(1000); 
       JobEventArgs e = new JobEventArgs(i); 
       OnChanged(e); 
      } 
     } 
    } 

    public class JobEventArgs 
    { 

     public int Counter { get; set; } 

     public JobEventArgs(int i) 
     { 
      Counter = i; 
     } 
    } 
} 

回答

3

對我來說這看起來很好。實際上你使用觀察者模式的。這只是c#的很好的事件語法,消除了界面並減少了樣板。

但是,那裏有很多冗餘代碼和其他可讀性問題。指定memeber如this.textBox1this.Invoke(...)

  • this限定符是冗餘的。
  • 嘗試始終爲方法指定可見性,如privatepublic
  • 一個合適的委託會圍繞一個方法組自動創建,從而實現簡寫語法。例如:new Thread(myThread.MyJob)myThread.Changed += myThread_Changed
  • 考慮使用簡單的Action作爲事件處理程序委託類型而不是自定義(ChangedCallback)。然後,myThread_Changed方法可以接受一個int作爲單個參數,從而允許刪除大量冗餘類型。
  • 爲了避免問題,在檢查null和調用之前先創建事件的線程本地副本。

像這樣:

JobEventHandler tmp = Changed; 
if (tmp != null) tmp(this, e); 
+0

+1的第一部分 - 我不認爲對網絡的東西確實增加了什麼,雖然。 – 2011-03-30 07:40:35

+0

這確實是觀察者模式。知道我理解它。首選示例(http://en.wikibooks.org/wiki/Computer_Science_Design_Patterns/Observer)。謝謝。 – 2011-03-30 07:42:13

+0

@Patrick Klug ops,錯誤地解釋了這個問題 - 認爲問題的一部分是「這在網絡環境中效果不佳」:-P – vidstige 2011-03-30 08:38:00

3

您的代碼不精。

  1. 爲什麼你不讓你的線程類創建線程?這更合乎邏輯,並提供了一個很好的封裝:
  2. 你不應該在類中聲明委託,它會使重構變得更難。
  3. 如果您正在線程中睡覺,爲什麼不使用Timer來代替?

public partial class Form1 
{ 
    delegate void ChangedCallback(object sender, JobEventArgs e); 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     MyThread myThread = new MyThread(); 
     myThread.Changed += myThread_Changed; 
     myThread.Start(); 
    } 

    void myThread_Changed(object sender, JobEventArgs e) 
    { 
     if (this.textBox1.InvokeRequired) 
     { 
      ChangedCallback d = new ChangedCallback(myThread_Changed); 
      this.Invoke(d, new object[] { sender, e }); 
     } 
     else 
     { 
      textBox1.Text += e.Counter; 
     } 
    } 
} 


public class MyThread 
{ 
    private Thread _thread; 

    public MyThread() 
    { 
     _thread = new Thread(WorkerFunc); 
    } 

    public void Start() 
    { 
     _thread.Start(); 
    } 

    // use the = {} pattern since you are using multithreading. 
    public event JobEventHandler Changed = {}; 

    protected virtual void OnChanged(JobEventArgs e) 
    { 
     Changed(this, e); 
    } 

    private void WorkerFunc() 
    { 
     for (int i = 0; i < 1000; i++) 
     { 
      Thread.Sleep(1000); 
      JobEventArgs e = new JobEventArgs(i); 
      OnChanged(e); 
     } 
} 

// A delegate type for hooking up change notifications. 
public delegate void JobEventHandler(object sender, JobEventArgs e); 
+0

1.正確。 2.正確3. Thread.Sleep(1000)應該被讀爲//工作...謝謝 – 2011-03-30 08:40:01