你真的可以等待条件变量与WaitFor ...对象?

时间:2016-05-30 09:25:04

标签: c++ windows winapi synchronization


我试图在许多CONDITION_VARIABLE上实施某种等待。
The answers here意味着在处理Windows API(以及互联网上的更多地方)时,WaitForMultipleObjects等是有效选项,但似乎并非如此。

首先,在MSDN文档中没有写到Windows Condition变量是WaitFor...函数的有效参数。
其次,WaitFor...似乎只接受HANDLE类型作为参数,它基本上是一个内核对象。但是PCONDITION_VARIABLE实际上不是HANDLE 最后,尝试使用条件变量(作为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";
    }

所以,你真的可以等待一个条件变量,还是只是一个都市传奇?

2 个答案:

答案 0 :(得分:5)

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

  

条件变量是同步原语,它使线程能够等到特定条件发生。条件变量是不能跨进程共享的用户模式对象。

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

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

  

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

     
      
  • 更改通知
  •   
  • 控制台输入
  •   
  • 事件
  •   
  • 内存资源通知
  •   
  • 互斥
  •   
  • 过程
  •   
  • 信号量
  •   
  •   
  • 等待计时器
  •   

他们都有相同的清单,所以没有混淆。

从技术上讲(我们在这里深入研究未记录的实现细节,所以你不应该依赖它作为福音),Win32 WaitForSingleObjectWaitForMultipleObjects函数建立在{{1内核子系统提供的{}和KeWaitForSingleObject函数。您可以将内核支持的对象划分为三个基本类别:调度程序对象,I / O对象/数据结构以及其他所有类别。第一类调度程序对象是最低级别的对象,它们都在其主体中使用相同的KeWaitForMultipleObjects数据结构表示。 Dispatcher对象是“可等待”的唯一对象类型。根据定义,正是这个DISPATCHER_HEADER结构使对象可以等待。如果使用此数据结构表示对象,则可以将其传递给内核同步函数。因此,相同的规则将适用于Win32函数。

整个问题似乎是基于Managu在his answer中做出的一个声明:“Windows已将WaitForMultipleObjects作为aJ发布,如果您愿意将代码限制为Windows同步原语。“也许他不认为条件变量(因为它们是由Windows实现的)是同步原语,或者他可能是错的。他引用的aJ的答案非常明确地指出DISPATCHER_HEADER用于“等待多个内核对象”,并且我们已经确定条件变量不是内核对象。无论哪种方式,我都没有看到任何有关“城市传说”的证据,你可以做到这一点。

显然,您无法将WaitForMultipleObjects系列函数与WaitForXxxboost::condition_variable或其他任何内容一起使用。我相信你已经知道了,但是你的问题让一些人感到困惑,因为它链接到一个引用Boost实现的问题。

我不清楚为什么你需要同时等待多个条件变量。我猜你可以编写自己的条件变量实现,基于经典的Win32同步原语,例如互斥,你可以等待std::condition_variable。您可以在线找到此类代码的示例,因为在Vista之前,条件变量不会成为操作系统的一部分。例如,this article讨论了在Windows中实现条件变量的策略,因为它们是由POSIX Pthreads规范定义的。您还可以考虑使用Event Objects

答案 1 :(得分:5)

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

首先,WaitForXxx函数(主要)在调度程序对象上运行 - 内核对象的一个​​子集,包括定时器,事件,互斥体,sempahores,线程和进程(以及一些内部对象类型,如{{1具有KAGTE的s和KQUEUE s,但不能访问令牌或文件映射对象)。它肯定不会在内核不知道的用户模式构造上工作。

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