2011-11-03 116 views
9

我有一個線程正在做一些處理。我希望能夠在執行過程中停止此線程,以某種方式保存它的位置(以及它正在運行的對象的狀態),然後從該位置在稍後的日期繼續(因此在我的計算機重新啓動後)。如何在執行過程中暫停,保存狀態,並在稍後繼續從同一點繼續?

在C#中這是不可能的吧?如果不是,那麼實現此功能的恰當設計是什麼?

所以我最初的願望就是擁有像

class Foo : Task { 
    void override Execute(){ 
     //example task 
     while(someCondition){ 
     ...do stuff... 
     } 
    } 
} 

,並能夠暫停/保存在該功能中的任何一點。當功能結束時,每個人都知道它已完成。 作爲替代,這也許是更好的方式來做到這一點

class Foo : Task { 


    void override Execute(State previousState){ 
     //set someCondition, other stuff 
     //IsPaused = false; 
     previousState.setUpStuff(); 

     //example task 
     while(someCondition){ 
      ...do stuff... 
      if(base.IsPauseRequested){ 
       base.UpdateState(); //this would be a bit different but just to get the idea 
       base.IsPaused = true; 
       return; 
      } 
     } 

     base.RaiseNotifyTaskComplete(); 
    } 

} 

所以第一種情況是誰需要繼承我的基類,因爲他們只需要落實執行功能的其他人簡單得多。但是,在第二種情況下,他們必須考慮以前的狀態,並管理存在良好暫停點的位置。有一個更好的方法嗎?

回答

4

你想要什麼可以通過一個可序列化的狀態機來完成。基本上,你可以將你的本地變量改爲類中的字段,並添加一個保持狀態的字段 - 原始方法代碼中的位置。此課程將爲[Serializable],它將有一個方法,如MoveNext(),它會完成一項工作並返回。工作時,您可以循環調用此方法。當你想停止時,你等到當前的調用結束後,跳出循環,然後將狀態機序列化到磁盤。

基於原始方法的複雜性以及您希望「檢查點」的頻率如何(當方法返回並且您可以選擇繼續或不時)時,狀態機可以像只有一個狀態那樣簡單,或者相當複雜。

C#編譯器在編譯迭代器塊(和C#5的async方法)時會執行非常類似的轉換。但它不是爲了這個目的,它不標記生成的類[Serializable],所以我不認爲你可以使用它。儘管閱讀一些關於如何實現這種轉變的文章可能會幫助你自己也做同樣的事情。

0

我無法回答C#,但通常這個問題被稱爲Persistence,並沒有一般的簡單方法來解決它(除非語言和系統提供它)。你不能以一個線程來推理,因爲你正在考慮的線程正在引用其他(全局或堆)數據。該問題也與garbage collection有關(因爲垃圾收集器和持久性機制都傾向於掃描整個活動堆)。

0

你可以用表達式樹或方法鏈設置類似的東西。爲不可中斷的最小「原子」工作單元設置lambdas或小方法。然後,將它們與一個「主管」連接在一起,按順序執行這些塊中的每一個,但可以被告知停止它在指令之間的操作,保存它在鏈中的位置,返回並等待恢復。如果你想要一個模式的名字,你可以把它稱爲Visitor的變體。

+0

這是一個很好的想法,我在想這樣的事情......幾乎就像一個充滿函數指針(代表)的數組。所以我只是沿着數組移動一個指針。我的這個想法的問題是,我希望我的基類被其他人使用。我認爲做這樣的事情會使情況過度複雜化(因爲很多人只會有隻有一個函數指針的任務)。不過,我喜歡這個主意。 – i8abug

0

您希望在進程暫停時序列化對象的狀態,然後在重新啓動後將其反序列化。

一個非常幼稚的實現是在你的Task類的Serialize/Deserialize上創建兩個靜態方法,它們使用Linq在XML中讀取/寫入對象的狀態。當任務暫停時,調用Serialize將對象轉儲爲xml到磁盤,當它重新啓動時,調用Deserialize讀取xml。還有可能更健壯的類XmlSerializer

無論這是一個複雜的問題,一個概念上簡單的解決方案。

+0

這聽起來像你基本上贊同我在那裏用IsPaused變量的方法,對吧?我沒有想太多關於如何序列化,但可能像你說的。我希望能有更好的方式來做到這一點,但也許這是處理這種情況的標準方法。 – i8abug

+0

如果你想暫停它,你需要保存對象的狀態,並在稍後再回來。所以,是的,當你暫停並反序列化你調用'setupStuff' – Jason

1

這可以很容易地使用WF實現......它具有明確暫停和恢復任務的所有工作(並且需要爲您保留持久性)。 Check out this link.

可能不適合你想要的東西,但也許值得調查。