这会导致事件驱动编程中的竞争条件吗?
我正在离散模拟器中编写一个基于代理的小型交互模拟,并开始编写一些如下所示的代码。我之前没有接触过事件驱动编程,但并没有真正观察到这种情况。我想知道以下代码在更新 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)?有什么建议吗?
I am writing a small agent-based interaction simulation in a discrete simulator and am beginning to write some code that looks like the following. I have not some event-driven programming before but did not really observe this situation. I am wondering if the following piece of code will lead to a race condition while updating the value of 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
}
}
My understanding is that at currentTime() + 5
both the agents receive the message at the same time because both the events are happening at the same logical time so I should see the number of messages to be 2? Or will I see some strange race condition happening and the value is dependent on the scheduler (i.e. it could end up printing 1 or 2)? Any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
答案取决于事件传输的实现,并且在这个意义上与语言无关。
在我使用过的所有系统中,每条消息都会单独放入事件队列中,接收代理会按顺序从该队列中取出事件。假设您有一个线程生成消息,并且一个事件从队列中取出消息,我看不到出现竞争条件的机会。
如果您的事件队列具有某种智能,可以尝试根据时间戳合并事件,则您在接收代理中只会看到一个事件。我不知道有一个通用系统可以做到这一点(尽管某些 UI 系统可能会将两次快速鼠标单击合并为双击......但这是特定事件系统的特定行为,而不是与语言/平台无关)。
The answer depends on the implementation of your event transport and is not language agnostic in that sense.
In all systems I have worked with, each message would be placed separately into an event queue and the receiving agent would take events off of that queue in order. Assuming you have one thread generating messages and one event taking messages off of the queue, I don't see an opportunity for a race condition.
If your event queue has some intelligence that attempts to consolidate events based on the timestamp, you would only see one event in the receiving agent. I'm not aware of a common system that does that (though some UI systems may for example consolidate two rapid mouse clicks to a double click... but that's specific behavior of a specific event system and not language/platform agnostic).
不,尽管代理代码非常可疑并且看起来很危险,但我不认为在这种情况下它会产生竞争条件:msgsRcvd 应该始终以正确的总数。即使调度程序在增量之前中断agent1,在我看来,控制权总是会回来让增量完成。如果控制器获得控制权,那么它可能会报告MsgsRcvd的不准确内容,但那又怎样呢? MsgsRcvd 很快恢复同相。
不过,这确实是一段看起来很可怕的代码。当我查看此类代码时,我总是想将 MsgsRcvd 的增量向上移动到控制器中,在那里公开一个将执行增量的函数。但在这种情况下,这只会让我感觉好一些;它不会改变逻辑,也不会解决 MsgsRcvd 偶尔暂时不准确的“问题”(如果是一个问题)。
No, even though the agent code is highly suspect and looks dangerous, I don't see that in this case it produces a race condition: msgsRcvd should always end up with the correct total. Even if the scheduler interrupts agent1 just before the increment, it seems to me that control will always come back to let that increment complete. If the controller gets control, then it might be that it will report the inaccurate contents of MsgsRcvd, but so what? MsgsRcvd quickly gets back in phase.
It sure is a scary-looking piece of code, though. When I'm looking at this kind of code, I always want to move the increment of MsgsRcvd up into the controller, exposing a function there that will do the increment. But that would only make me feel better in this case; it wouldn't change the logic and it wouldn't solve the "problem" (if it is one) of MsgsRcvd being temporarily inaccurate once in a while.
最初要提到的是,没有与语言/平台无关的方法来回答这个问题,但 Eric J. 已经涵盖了这一点。
在 C++ 中,除非您的平台保证回调将被序列化,否则编写的代码将不安全。原因是增量运算符不是原子的,如果两个线程同时尝试更新值,则根据获取、添加和存储的顺序,可能会发生任意数量的事情。
如果这个平台的设计确实考虑了并发性,那么应该有一个“互锁/原子”API 来提供您所需的功能。
Originally was going to mention that there is no language/platform agnostic way to answer this question, but Eric J. has that covered.
In C++ that code as written will not be safe unless your platform guarantees that the callbacks will be serialized. The reason is the increment operator is not atomic and if two threads are concurrently trying to update the value, any number of things could happen depending on the order of the fetch, add, and store.
If this platform was truly designed with concurrency in mind, then there should be an "interlocked/atomic" api that provides the feature you need.