2011-11-03 7 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(); 
    } 

} 

を行うには良い方法です。しかし、第2のケースでは、以前の状態を考慮し、良好な一時停止点が存在する場所を管理する必要があります。これを行うより良い方法はありますか?

答えて

4

あなたが望むものは、シリアライズ可能なステートマシンによって達成できます。基本的には、ローカル変数をクラス内のフィールドに変更し、元のメソッドのコード内の位置を保持するフィールドを追加します。このクラスは[Serializable]になり、MoveNext()のような1つのメソッドがあり、これは作業と戻り値を行います。作業中は、ループ内でこのメソッドを呼び出します。停止したいときは、現在の呼び出しが終了するまで待ってからループから抜け出し、ステートマシンをディスクにシリアル化します。

元の方法の複雑さと、「チェックポイント」を使用する頻度(MoveNext()メソッドが返され、続行するかどうかを選択できる)に基づいて、ステートマシンは1つの状態、または非常に複雑です。

C#コンパイラは、イテレータブロック(およびC#5のasyncメソッド)をコンパイルするとき、非常に似た変換を行います。しかし、それはこの目的のためではなく、生成されたクラス[Serializable]をマークしていないので、私はあなたがそれを使用できるとは思わない。この変換が実際にどのように行われたかについてのいくつかの記事を読むことで、同じことを自分で行うのに役立つかもしれませんが。

0

C#についてはお答えできませんが、一般的にはこの質問はPersistenceと呼ばれており、言語とシステムが提供している場合を除き、一般的な解決方法はありません。考慮しているスレッドが他の(グローバルまたはヒープ)データを参照しているため、あるスレッドの理由で推論することはできません。この質問は、garbage collectionにも関連しています(ガベージコレクタと永続性メカニズムの両方がライブヒープ全体をスキャンする傾向があるため)。

0

おそらく、このようなものを式ツリーまたはメソッドチェーンで設定できます。中断されない最小の「アトミック」単位の作業のためのラムダまたは小さなメソッドを設定します。次に、これらのチャンクを順番に実行する「スーパーバイザー」と一緒にチェーン化しますが、指示の間に何をしているのかを停止し、チェーンに沿った位置を保存し、復帰して再開するのを待つことができます。パターンの名前が必要な場合は、それを訪問者のバリエーションと呼びます。

+0

これは良い考えで、そのようなものについては疑問に思っていました。ほぼ関数ポインタ(デリゲート)でいっぱいの配列に似ています。だから、私はちょうど配列に沿ってポインタを移動します。このアイデアの私の問題は、自分のベースクラスを他の人が使うようにすることです。私はこのようなことをすると、状況が複雑になりすぎると思います(多くの人が配列内に関数ポインタを1つしか持たないタスクがあるため)。私はこの考えが好きです。 – i8abug

0

プロセスが一時停止したときにオブジェクトの状態をシリアル化し、再起動した後にオブジェクトを逆シリアル化したいとします。

非常に素朴な実装では、XMLでオブジェクトの状態を読み書きするためにLinqを使用するTaskクラスSerialize/Deserializeに2つの静的メソッドを作成します。タスクが一時停止しているときにSerializeを呼び出すと、オブジェクトをxmlとしてディスクにダンプします。再起動すると、xmlを読み込むDeserializeを呼び出します。より堅牢性の高いXmlSerializerクラスもあります。

これは複雑な問題で、概念的には簡単な解決策です。

+0

私はIsPaused変数を持っているメソッドを基本的に支持しているようですね。私はどのようにシリアライズするかについてはあまり考えていませんが、おそらくあなたのように言います。私はそれを行うよりよい方法があると思っていましたが、おそらくそのような状況に対処するための標準的な方法です。 – i8abug

+0

フックや詐欺では、オブジェクトの状態を一時停止し、後でその状態に戻す必要がある場合は、オブジェクトの状態を保存する必要があります。だから、あなたはあなたが 'setupStuff'と呼ぶ場所を一時停止して逆シリアル化するときにシリアル化します – Jason

1

これは、WFを使用して簡単に実現できます。これは、すべての配管が明示的にタスクを一時停止して再開すること(そしてそれはあなたのために永続性を保つ)です。 Check out this link.

おそらくあなたが望むものには適していないかもしれませんが、調査の価値があるかもしれません。

関連する問題