你真的能用WaitFor..等待条件变量吗..对象

Can you really wait on Condition Variable with WaitFor...Object(s)?

本文关键字:条件 变量 对象 等待 WaitFor 真的      更新时间:2023-10-16


我正试图在许多CONDITION_VARIABLE上实现某种等待
这里的答案意味着WaitForMultipleObjects等在处理Windows API(以及互联网上的许多地方)时是有效的选项,但事实并非如此。

首先,MSDN文档中没有任何地方写到Windows Condition变量是WaitFor...函数的有效参数
其次,WaitFor...似乎只接受HANDLE类型作为参数,这基本上是一个内核对象。但CCD_ 6并不是真正的CCD_
最后,尝试使用条件变量(同时作为PCONDITION_VARIABLE和未记录的CONDITION_VARIABLE::Ptr)会使函数返回错误代码6(无效句柄)

例如:

CONDITION_VARIABLE cv;
InitializeConditionVariable(&cv);
auto res = WaitForSingleObject(cv.Ptr, INFINITE); //returns immediately
if (res != WAIT_OBJECT_0) { 
auto ec = GetLastError();
std::cout << ec << "n";
}

那么,你真的能等待一个条件变量吗?还是它只是一个城市传说?

我不这么认为,也没有任何意义。

首先,WaitForXxx函数(主要)在调度器对象上运行,调度器对象是内核对象的子集,包括定时器、事件、互斥、信号、线程和进程(以及一些内部对象类型,如KAGTEKQUEUE,但不包括访问令牌或文件映射对象),它们具有DISPATCHER_HEADER。它肯定不会在内核不知道的用户模式结构上工作。

其次,请注意,当您在条件变量上休眠("等待")时,您必须使用正确的函数SleepConditionVariableCSSleepConditionVariableSRW指定这是基于关键部分的条件变量还是基于SRWL的条件变量。因此,Windows(不仅仅是内核)不知道你要传递什么样的条件变量,但它需要这些信息才能正确运行。由于您没有向WaitForXxx提供此信息,因此它们不能与条件变量一起使用。

问题的简单答案是。不能将WaitForXxx函数与Windows同步API提供的条件变量一起使用。来自链接文档:

条件变量是同步基元,使线程能够等待特定条件发生。条件变量是不能在进程之间共享的用户模式对象。

WaitForXxx函数接受通用HANDLE类型的参数,该类型表示内核对象的句柄。条件变量是用户模式对象,而不是内核的对象,因此不能将它们与这些函数一起使用,因为它们只能与内核对象一起使用。

此外,这些函数的文档非常明确地说明了它们可以等待哪些类型的对象,而条件变量不在该列表中。例如,WaitForMultipleObjects说:

WaitForMultipleObjects函数可以在lpHandles数组中指定以下任何对象类型的句柄:

  • 更改通知
  • 控制台输入
  • 事件
  • 内存资源通知
  • Mutex
  • 流程
  • 信号量
  • 螺纹
  • 等待计时器

它们都有相同的列表,所以没有混淆。

从技术上讲(我们在这里深入讨论了未记录的实现细节,所以不应该把它当作福音),Win32WaitForSingleObjectWaitForMultipleObjects函数是基于内核子系统提供的KeWaitForSingleObjectKeWaitForMultipleObjects函数构建的。您可以将内核支持的对象划分为三个基本类别:调度器对象、I/O对象/数据结构和其他所有对象。第一类调度器对象是最低级别的对象,它们在主体中都使用相同的DISPATCHER_HEADER数据结构来表示。Dispatcher对象是唯一可"等待"的对象类型。根据定义,正是这种DISPATCHER_HEADER结构使对象可等待。如果使用此数据结构表示对象,则可以将其传递给内核同步函数。因此,相同的规则将适用于Win32函数。

整个问题似乎是基于Managu在回答中的一句话:"Windows发布了WaitForMultipleObjects,如果你愿意将代码限制为Windows同步原语,这可能是一个解决方案。">也许他不认为条件变量(因为它们是由Windows实现的)是同步原语,或者他只是错了。aJ的回答(他提到的)非常清楚地表明WaitForMultipleObjects用于"等待多个内核对象",并且我们已经确定条件变量不是内核对象。无论哪种方式,我都看不到任何证据表明你可以做到这一点。

显然,不能将WaitForXxx函数族与boost::condition_variablestd::condition_variable或其他任何函数一起使用。我相信你已经知道了,但你的问题让一些人感到困惑,因为它链接到了一个涉及Boost实现的问题。

我并不特别清楚为什么需要同时等待多个条件变量。我想您可以根据经典的Win32同步原语(如互斥体)编写自己的条件变量实现,然后使用WaitForMultipleObjects等待。您可能可以在网上找到此类代码的示例,因为条件变量直到Vista才成为操作系统的一部分。例如,本文讨论了在Windows中实现条件变量的策略,因为它们是由POSIXPthreads规范定义的。您还可以研究使用事件对象。