事件驱动模拟类
我正在完成 Bjarne Stroustrup 所著《C++ 编程语言》中的一些练习。 我对第 12 章末尾的问题 11 感到困惑:
(*5) 设计和实现用于编写事件驱动模拟的库。 提示:。 ...类任务的对象应该能够保存其状态并恢复该状态,以便它可以作为协程运行。 特定任务可以定义为从任务派生的类的对象。 任务要执行的程序可以定义为虚拟函数。 ...应该有一个调度程序来实现虚拟时间的概念。 ...任务需要进行通信。 为此设计一个类队列。 ...
我不确定这到底要求什么。 任务是一个单独的线程吗? (据我所知,没有系统调用就不可能创建一个新线程,而且由于这是一本关于 C++ 的书,我不相信这是其意图。)如果没有中断,如何启动和停止正在运行的线程功能? 我认为这将涉及繁忙的等待(也就是说,不断循环并检查条件),尽管我看不出如何将其应用于可能在一段时间内不会终止的函数(例如,如果它包含无限循环) 。
编辑:请参阅我下面的帖子了解更多信息。
I am working through some of the exercises in The C++ Programming Language by Bjarne Stroustrup. I am confused by problem 11 at the end of Chapter 12:
(*5) Design and implement a library for writing event-driven simulations. Hint: <task.h>. ... An object of class task should be able to save its state and to have that state restored so that it can operate as a coroutine. Specific tasks can be defined as objects of classes derived from task. The program to be executed by a task might be defined as a virtual function. ... There should be a scheduler implementing a concept of virtual time. ... The tasks will need to communicate. Design a class queue for that. ...
I am not sure exactly what this is asking for. Is a task a separate thread? (As far as I know it is not possible to create a new thread without system calls, and since this is a book about C++ I do not believe that is the intent.) Without interrupts, how is it possible to start and stop a running function? I assume this would involve busy waiting (which is to say, continually loop and check a condition) although I cannot see how that could be applied to a function that might not terminate for some time (if it contains an infinite loop, for example).
EDIT: Please see my post below with more information.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(8)
提示:
。
是对早期版本的 CFront 附带的旧协作多任务库的引用(您也可以在该页面下载)。
如果您阅读论文“A Set of C++ Classes for Co-常规风格编程”的事情会变得更有意义。
添加一点:
我还不是一个足够老的程序员,无法使用任务库。 然而,我知道 C++ 是在 Stroustrup 在 Simula 中编写了一个模拟之后设计的,该模拟具有许多与任务库相同的属性,所以我一直对它感到好奇。
如果我要实现书中的练习,我可能会这样做(请注意,我没有测试过这段代码,甚至没有尝试编译它):
class Scheduler {
std::list<*ITask> tasks;
public:
void run()
{
while (1) // or at least until some message is sent to stop running
for (std::list<*ITask>::iterator itor = tasks.begin()
, std::list<*ITask>::iterator end = tasks.end()
; itor != end
; ++itor)
(*itor)->run(); // yes, two dereferences
}
void add_task(ITask* task)
{
tasks.push_back(task);
}
};
struct ITask {
virtual ~ITask() { }
virtual void run() = 0;
};
我知道人们会不同意我的一些选择。 例如,使用结构体作为接口; 但是结构体的行为默认是公共继承(默认情况下从类继承是私有的),并且我看不到从接口私有继承有任何价值,那么为什么不将公共继承设置为默认继承呢?
这个想法是,调用 ITask::run() 将阻塞调度程序,直到任务到达可以中断的点,此时任务将从 run 方法返回,并等待调度程序再次调用 run 来执行任务。继续。 “协作多任务处理”中的“协作”意思是“任务说何时可以被中断”(“协程”通常意味着“协作多任务处理”)。 一个简单的任务可能只在它的 run() 方法中做一件事,一个更复杂的任务可能会实现一个状态机,并且可能使用它的 run() 方法来确定对象当前处于什么状态,并根据情况调用其他方法就那个状态。 为了使其发挥作用,任务必须偶尔放弃控制权,因为这就是“协作多任务处理”的定义。 这也是所有现代操作系统不使用协作多任务处理的原因。
此实现不 (1) 遵循公平调度(可能保留任务的 run() 方法中花费的时钟周期的运行总数,并跳过相对于其他任务使用过多时间的任务,直到其他任务“赶上”) ,(2) 允许删除任务,甚至 (3) 允许停止调度程序。
至于任务之间的通信,您可以考虑查看 Plan 9 的 libtask 或 Rob Pike 的 newsqueak 获取灵感(“Newsqueak 的 UNIX 实现”下载包括一篇论文“Newsqueak 的实现”,该论文以有趣的方式讨论了消息传递)虚拟机)。
但我相信这就是斯特鲁斯特鲁普心目中的基本骨架。
离散事件模拟的通用结构基于以时间值为关键的优先级队列。 从广义上讲,它是这样的:
While (not end condition): Pop next event (one with the lowest time) from the priority queue Process that event, which may generate more events If a new event is generated: Place this on the priority queue keyed at its generated time
协同例程将模型的视图从以事件为中心更改为以实体为中心。 实体可以经历一些生命周期(例如接受作业、获取资源X、处理作业、释放资源X、将作业放入队列中以进行下一步)。 这在某种程度上更容易编程,因为抓取资源是通过类似信号量的同步原语来处理的。 作业和同步原语生成事件并在幕后将它们排队。
这提供了一个概念上类似于操作系统中的进程的模型,以及当进程的输入或它请求的共享资源可用时唤醒进程的调度程序。 协同例程模型使仿真变得更容易理解,这对于仿真复杂系统很有用。
这是对 titandecoy 对 SottieT812 的回答的评论的回应。 它对于评论来说太大了,所以我决定将其作为另一个答案。
它是事件驱动的,因为模拟状态仅响应事件而改变。 例如,假设您有两个事件导弹发射和导弹撞击。 当执行启动事件时,它会计算出影响的时间和地点,并在适当的时间安排影响事件。 导弹的位置在发射和撞击之间不会被计算,尽管它可能有一个可以被其他对象调用的方法来获取特定时间的位置。
这与时间驱动模拟形成对比,在时间驱动模拟中,导弹(以及模拟中的所有其他对象)的确切位置是在每个时间步长(例如 1 秒)后计算的。
根据模型的特征、所需答案的保真度以及许多其他因素,事件驱动或时间驱动的模拟可能会表现更好。
编辑:如果有人有兴趣了解更多信息,请查看冬季模拟会议中的论文
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
这是我对“事件驱动模拟”的理解:
大多数生产事件驱动的模拟都在单个线程中运行。 它们本质上可能很复杂,因此尝试同步多线程模拟往往会增加指数级的复杂性。 话虽如此,多进程军事模拟有一个标准,称为分布式交互式模拟 (DIS)它使用预定义的 TCP 消息在进程之间传输数据。
编辑:定义建模和模拟之间的区别很重要。 模型是系统或过程的数学表示。 模拟是根据在一段时间内执行的一个或多个模型构建的。 同样,事件驱动的模拟从一个事件跳到另一个事件,而时间驱动的模拟则以恒定的时间步长进行。
Here's my understanding of an "event-driven simulation":
Most production event-driven simulations run in a single thread. They can be complex by their very nature, so trying to synchronize a multi-threaded simulation tends to add exponential layers of complexity. With that said, there's a standard for multi-process military simulations called Distributive Interactive Simulation (DIS) that uses predefined TCP messages to transmit data between processes.
EDIT: It's important to define a difference between modeling and simulation. A model is a mathematical representation of a system or process. A simulation is built from one or more models that are executed over a period of time. Again, an event driven simulation hops from event to event, while a time driven simulation proceeds at a constant time step.