- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想为 2 个线程实现一个消息队列。线程 #1 将弹出队列中的消息并处理它。线程 #2 会将消息插入队列。
这是我的代码:
Thread #1 //Pop message and process
{
while(true)
{
Lock(mutex);
message = messageQueue.Pop();
Unlock(mutex);
if (message == NULL) //the queue is empty
{
//assume that the interruption occurs here (*)
WaitForSingleObject(hWakeUpEvent, INFINITE);
continue;
}
else
{
//process message
}
}
}
Thread #2 //push new message in queue and wake up thread #1
{
Lock(mutex);
messageQueue.Push(newMessage)
Unlock(mutex);
SetEvent(hWakeUpEvent);
}
问题是在某些情况下 SetEvent(hWakeUpEvent)
会在 WaitForSingleObject()
之前被调用(注意 (*) ),这会很危险。
最佳答案
你的代码没问题!
SetEvent 和 WaitForSingleObject 之间的计时没有实际问题:关键问题是事件上的 WaitForSingleObject 将检查事件的状态,并等待直到它被触发。如果事件已经触发,它将立即返回。 (从技术上讲,它是电平触发的,而不是边沿触发的。)这意味着如果在调用 WaitForSingleObject 之前或期间调用 SetEvent 都可以; WaitForSingleObject 在任何一种情况下都会返回;立即或稍后调用 SetEvent 时。
(顺便说一句,我假设在这里使用自动重置事件。我想不出使用手动重置事件的充分理由;您最终不得不在 WaitForSingleObject 返回后立即调用 ResetEvent;并且有一个危险是如果你忘记了这一点,你可能最终会等待一个你已经等待但忘记清除的事件。此外,在检查基础数据状态之前重置是很重要的,否则如果在数据被调用之间调用 SetEvent处理并调用 Reset(),你会丢失该信息。坚持使用自动重置,你就可以避免这一切。)
--
[编辑:我将 OP 的代码误读为在每次唤醒时执行一次“弹出”,而不是只等待空的,因此下面的评论指的是该场景的代码。 OP 的代码实际上等同于下面的第二个建议修复。所以下面的文字实际上是在描述一个有点常见的编码错误,其中事件被用作信号量,而不是 OP 的实际代码。]
但是这里有一个不同的问题[或者,如果每次等待只有一个 pop...],那就是 Win32 Events 对象只有两种状态:unsignaled 和 signaled,所以你只能使用它们跟踪二进制状态,但不计数。如果您设置事件和已发出信号的事件,它将保持已发出信号,并且该额外的 SetEvent 调用的信息将丢失。
在那种情况下,可能发生的情况是:
有两种解决方法:经典的 Comp.Sci 方法是使用信号量而不是事件——信号量本质上是对所有“Set”调用进行计数的事件;相反,您可以将事件视为最大计数为 1 的信号量,它会忽略除该信号之外的任何其他信号。
另一种方法是继续使用事件,但是当工作线程被唤醒时,它只能假设队列中可能有一些项,它应该在之前尝试处理所有这些项它返回到等待——通常是通过将弹出项目的代码放在一个循环中,该循环弹出项目并处理它们直到它为空。该事件现在不用于计数,而是用于发出“队列不再为空”的信号。 (请注意,当您执行此操作时,您还可能遇到这样的情况:在处理队列时,您还处理了一个刚刚添加的项目并为其调用了 SetEvent,因此当工作线程到达 WaitForSingleObject 时,线程会唤醒但发现队列为空,因为该项目已被处理;起初这看起来有点令人惊讶,但实际上没问题。)
我认为这两者大致相同;两者各有利弊,但都是正确的。 (我个人更喜欢事件方法,因为它将“需要做某事”或“有更多数据可用”的概念与工作或数据的数量分离开来。)
关于c++ - WaitForSingleObject() 和 SetEvent() 函数之间同步的算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9570433/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!