2011-03-02 63 views
3

如果我有一個類基本線程問題

public Class foo 
{ 
    public foo() 
    { 
     myclass = new myclass(param) 
     myclass.initiateState(); 
     val = myclass.getValues(); 
    } 
} 

Class.initiateState()是這是在我的GUI構造函數,我想開始一個線程中運行運行一個漫長的過程,但下一行去同一個類獲取一些數據,但如果我在新線程中運行第一行,那麼在它完成之前就會執行它。

我該如何解決這個問題?

+5

嗨,你不應該加載數據無論如何在GUI的約束,GUI應該加載和顯示q uickly。 – 2011-03-02 13:19:12

回答

11

作爲BackgroundWorker

DoWork事件方法中,添加myClass.initiateState()調用。裏面的RunWorkerCompleted事件的方法,調用myClass.getValues();

這將導致initiateState到在後臺線程運行,完成時將觸發getValues GUI線程上。

另外,請注意,與Java相比,在C#中,使用大寫字母開始方法名稱是正常的。所以方法應該具有的名稱InitiateStateGetValues :)

+0

我認爲創建'BackgroundWorker'是語法開銷,如果你不需要取消和進度通知。 – Andrey 2011-03-02 13:25:11

+1

@Andrey--可能會更長一些,但對其他人來說很容易閱讀,反正也不會那麼長。如果他稍後需要進度通知(他說這是一項冗長的任務),那麼很容易擴展他現有的工作來實現這些變化。 – 2011-03-02 13:35:31

+0

+1我喜歡BackGroundWorker – 2011-03-02 14:04:55

4

最簡單的方法就是做:

public Class foo 
{ 
    public foo() 
    { 
     myclass = new myclass(param) 
     new Action(() => myclass.initiateState()).BeginInvoke(initiateStateFinished, null) 
    } 

    private void initiateStateFinished(IAsyncResult ar) 
    { 
     val = myclass.getValues(); 
     //other actions 
    } 
} 

,甚至更短的

public foo() 
    { 
     myclass = new myclass(param) 
     new Action(() => myclass.initiateState()) 
      .BeginInvoke(_ => val = myclass.getValues(), null) 
    } 
+0

我之前很少使用過Action,所以我在這裏有個問題。將在主GUI線程或後臺線程上調用initiateStateFinished方法嗎? – 2011-03-02 13:32:08

+0

@ØyvindKnobloch-Bråthen在背景之一 – Andrey 2011-03-02 14:06:47

1

所以,你要同時執行

myclass.initiateState(); 
    val = myclass.getValues(); 

在一個新的線程(val是一個返回值)?

你可以做到這一點很容易使用.NET 4.0 Tasks,因爲這樣的:

 var someBackgroundTask = new System.Threading.Tasks.Task<*return type of GetValue()*>(() => 
      { 
       myclass.initiateState(); 
       return myclass.getValue(); 
      }); 
     someBackgroundTask.Start(); 

,並在以後使用someBackgroundTask.Result來獲得,那麼,結果。唯一的問題是你需要等待(或檢查關鍵點),看看Task是否已完成。您可以使用someBackgroundTask.IsCompleted來檢查它是否仍在工作,或者使用someBackgroundTask.Wait()等待它完成。

編輯:再次,上面的建議可能會更好。 ;)

0

從給出的例子看來,應該在單獨的線程中運行整個foo類。爲了適用於其他情況,我將假設foo中有其他內容,不應該將其作爲另一個線程運行。


首先在foo創建的DoWork方法:

private void DoWork() { 
    myclass = new myclass(param); 
    myclass.initiateState(); 
    val = myclass.getValues(); 
} 

然後改變構造函數來運行,作爲一個線索:

public foo() { 
    Thread workerThread = new Thread(this.DoWork); 
    /* ... do other stuff ... */  
} 

看看這個:http://msdn.microsoft.com/en-us/library/7a2f3ay4.aspx

+2

如果GUI線程也使用了val,那麼這可能會導致一些問題,但這並不是由OP指定的。以爲我會提到它;) – 2011-03-02 13:30:45