如何在执行期间暂停,保存状态,并在以后从同一点继续?

时间:2011-11-03 14:41:57

标签: c# design-patterns

我有一个正在进行一些处理的线程。我希望能够在执行期间停止此线程,以某种方式保存它的位置(以及它正在操作的对象的状态),然后在以后从该位置继续(因此在我的计算机重新启动后)。

在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();
    }

}

因此,对于需要继承我的基类的其他人来说,第一种情况要简单得多,因为他们只需要实现Execute函数。但是,在第二种情况下,他们必须考虑先前的状态,并管理存在良好暂停点的位置。有更好的方法吗?

5 个答案:

答案 0 :(得分:5)

您可以通过可序列化的状态机来完成您想要的任务。基本上,您将局部变量更改为类中的字段,并添加一个保持状态的字段 - 原始方法的代码中的位置。这个类将是[Serializable],它将有一个像MoveNext()这样的方法,它可以完成一项工作并返回。工作时,您可以循环调用此方法。当你想要停止时,你要等到当前调用结束,中断循环,然后将状态机序列化到磁盘。

基于原始方法的复杂性以及您想要“检查点”的频率(当MoveNext()方法返回时,您可以选择是否继续),状态机可以像拥有一样简单只是一个国家,或相当复杂。

C#编译器在编译迭代器块(和C#5的async方法)时进行非常相似的转换。但它不是为了这个目的,它不标记生成的类[Serializable],所以我认为你不能使用它。虽然阅读一些关于如何实现这种转变的文章可能会帮助你自己做同样的事情。

答案 1 :(得分:1)

使用WF可以轻松实现这一点......它具有明确暂停和恢复任务的所有管道(并且它可以为您提供持久性)。 Check out this link.

可能不适合你想要的东西,但也许值得调查。

答案 2 :(得分:0)

我无法回答C#,但一般来说这个问题被称为Persistence,并且没有一般简单的方法来解决它(除非语言和系统提供它)。您无法根据一个线程进行推理,因为您正在考虑的线程正在引用其他一些(全局或堆)数据。这个问题也与garbage collection有关(因为垃圾收集器和持久性机制都倾向于扫描整个实时堆)。

答案 3 :(得分:0)

你可以用表达式树或方法链来设置这样的东西。为无法中断的最小“原子”工作单元设置lambdas或小方法。然后,将它们与“主管”链接在一起,“主管”将按顺序执行每个块,但可以告诉它停止在指令之间执行的操作,保存其沿链的位置,返回并等待恢复。如果您想要模式的名称,可以将其称为访问者的变体。

答案 4 :(得分:0)

您希望在进程暂停时序列化对象的状态,然后在重新启动后对其进行反序列化。

一个非常天真的实现是在Task类Serialize / Deserialize上创建两个静态方法,它们使用Linq以XML格式读取/写入对象的状态。当一个任务暂停时,调用Serialize将对象作为xml转储到磁盘,当它重新启动时,调用Deserialize读取xml。还有XmlSerializer类可能更健壮。

无论这是一个复杂的问题,还是一个概念上简单的解决方案。