0

我正在离散模拟器中编写一个基于代理的小型交互模拟,并开始编写一些如下所示的代码。我之前没有一些事件驱动的编程,但并没有真正观察到这种情况。我想知道以下代码是否会在更新msgRcvd.

// Following is the event-loop per-se
Controller {
    if (...) {
       SendMessage(currentTime() + 5, i,j)
       SendMessage(currentTime() + 5, i,k)
    }
    print currentTime(), msgsRcvd
    Schedule(currentTime()+1, Controller)
}

// The following function is called when an 
// agent receives a message
Receive(Agent agent) {
    if (...) {
       msgsRcvd++ // <-- this is a global variable
    }
}

我的理解是,currentTime() + 5两个代理同时收到消息,因为这两个事件都在同一逻辑时间发生,所以我应该看到消息数为 2?或者我会看到一些奇怪的竞争条件发生并且值取决于调度程序(即它最终可能打印 1 或 2)?有什么建议么?

4

3 回答 3

1

答案取决于您的事件传输的实现,并且在这个意义上与语言无关。

在我使用过的所有系统中,每条消息都将单独放入一个事件队列中,接收代理将按顺序从该队列中取出事件。假设您有一个线程生成消息和一个事件将消息从队列中取出,我看不到竞争条件的机会。

如果您的事件队列具有尝试根据时间戳合并事件的智能,您将只能在接收代理中看到一个事件。我不知道有一个通用系统可以做到这一点(尽管某些 UI 系统可能会将两次快速鼠标单击合并为一次双击……但这是特定事件系统的特定行为,而不是与语言/平台无关的)。

于 2011-10-04T22:39:05.587 回答
1

不,即使代理代码非常可疑并且看起来很危险,但我认为在这种情况下它不会产生竞争条件:msgsRcvd 应该始终以正确的总数结束。即使调度程序在增量之前中断 agent1,在我看来,控制总是会回来让增量完成。如果控制器获得控制权,那么它可能会报告MsgsRcvd的不准确内容,但那又如何呢?MsgsRcvd 很快恢复正常。

不过,这确实是一段看起来很吓人的代码。当我查看这种代码时,我总是想将 MsgsRcvd 的增量向上移动到控制器中,在那里公开一个将执行增量的函数。但这只会让我在这种情况下感觉更好。它不会改变逻辑,也不会解决 MsgsRcvd 偶尔暂时不准确的“问题”(如果有的话)。

于 2011-10-04T22:43:48.840 回答
1

最初是要提到没有与语言/平台无关的方式来回答这个问题,但 Eric J. 已经涵盖了这一点。

在 C++ 中,除非您的平台保证回调将被序列化,否则所编写的代码将不安全。原因是增量运算符不是原子的,如果两个线程同时尝试更新值,根据获取、添加和存储的顺序,可能会发生任何数量的事情。

如果这个平台的设计真的考虑到了并发性,那么应该有一个“互锁/原子”的 API 来提供你需要的功能。

于 2011-10-04T22:45:17.867 回答