如何在执行过程中暂停、保存状态并在以后从同一点继续
本文关键字:继续 一点 过程中 执行 暂停 状态 保存 | 更新日期: 2023-09-27 18:13:09
我有一个线程正在做一些处理。我希望能够在执行期间停止此线程,以某种方式保存它的位置(以及它正在操作的对象的状态),然后在以后的日期(因此在我的计算机重新启动后)从该位置继续。
在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函数。然而,在第二种情况下,他们必须考虑之前的状态,并管理哪里存在良好的暂停点。有更好的方法吗?
您想要的可以通过可序列化的状态机来完成。基本上,您可以将局部变量更改为类中的字段,并添加一个字段来保存状态—原始方法在代码中的位置。这个类将是[Serializable]
,它将有一个类似MoveNext()
的方法,它做了一件工作并返回。工作时,在循环中调用此方法。当您想要停止时,您可以等到当前调用结束,跳出循环,然后将状态机序列化到磁盘。
基于原始方法的复杂性和你想要"检查点"的频率(当MoveNext()
方法返回时,你可以选择继续或不继续),状态机可以像只有一个状态一样简单,也可以相当复杂。
c#编译器在编译迭代器块(和c# 5的async
方法)时会做非常类似的转换。但它不是为了这个目的,它没有标记生成的类[Serializable]
,所以我不认为你可以使用它。尽管阅读一些关于如何实际完成此转换的文章可能会帮助您自己完成相同的操作。
这可以很容易地实现使用WF…它具有显式暂停和恢复任务的所有管道(并为您处理持久性)。请看这个链接。
可能不适合你想要的,但也许值得研究。
我不能回答C#
,但一般来说,这个问题被称为持久性,并且没有通用的简单方法来解决它(除非语言和操作系统提供它)。您不能根据一个线程进行推理,因为您正在考虑的线程正在引用其他一些(全局或堆)数据。这个问题也与垃圾收集(因为垃圾收集器和持久性机制都倾向于扫描整个活动堆)和数据库(特别是NoSQL数据库)有关。因此,请阅读GC手册和操作系统的教科书,也请参阅OSDEV等网站。
请参阅此报告草案,阅读Queinnec的Lisp在Small Pieces一书中,并研究现有持久软件的源代码,包括RefPerSys(当然还有Mono, c#的开源实现)
当您希望在云计算上下文中持久化进程网络(或图)时,事情变得更加具有挑战性。然后在网上搜索面向智能体的编程。
在概念层面上,您的问题与延续传递风格和回调有关,您会发现许多acm赞助的会议(例如PLDI, ISMM)都讨论这个主题
您可以使用表达式树或方法链来设置类似的内容。为不能被中断的最小的"原子"工作单元设置lambda或小方法。然后,将它们与一个"监督器"链接在一起,该"监督器"将按顺序执行这些块,但可以被告知在指令之间停止正在做的事情,保存其沿链的位置,返回并等待恢复。如果你想要一个模式的名字,你可以把它叫做Visitor的变体
您希望在进程暂停时序列化对象的状态,然后在它重新启动时反序列化它。
一个非常幼稚的实现是在你的任务类Serialize/Deserialize上创建两个静态方法,它们使用Linq在XML中读取/写入对象的状态。当任务暂停时,调用Serialize将对象作为xml转储到磁盘,当任务重新启动时,调用Deserialize读取xml。还有XmlSerializer类,它可能更健壮。
不管这是一个复杂的问题,用一个概念上简单的解决方案。