C++ 使用引用包装器作为条件变量谓词

C++ 使用引用包装器作为条件变量谓词,c++,multithreading,c++11,boost,reference-wrapper,C++,Multithreading,C++11,Boost,Reference Wrapper,注意:以下内容同样适用于Boost.Thread和C++11线程 我有一个条件变量,这个条件实际上是一个简单的布尔变量 // assume these are global mutex m; condition_variable c; boolean b = false; 我想使用wait(lock,predicate)语法。例如,我可以使用lambda: c.wait(lock, [] () { return b; }); 但我认为应该有一种更惯用的方式将变量包装为可调用变量。所以我发现r

注意:以下内容同样适用于Boost.Thread和C++11线程

我有一个条件变量,这个条件实际上是一个简单的布尔变量

// assume these are global
mutex m;
condition_variable c;
boolean b = false;
我想使用
wait(lock,predicate)
语法。例如,我可以使用lambda:

c.wait(lock, [] () { return b; });
但我认为应该有一种更惯用的方式将变量包装为可调用变量。所以我发现
reference\u wrapper
提供了一个
操作符()
,用于检索包装的值。因此,我尝试:

c.wait(lock, cref(b));
但是g++(4.9.1)没有编译它,认为
没有匹配的函数来调用“(boost::reference_wrapper)(”
(如果我使用
std::ref
,错误会有所不同,但仍然没有编译)

reference\u wrapper
不应该作为条件变量的适当谓词吗?若否,原因为何?在这种情况下,
b
的正确包装是什么

编辑:所以@Praetorian很正确地解释了我的错误,但是,Boost或standard上真的没有这样的东西吗(这里可能有错误):

模板
可调用的结构{
T&objref;
as_可调用(T&r):objref(r){}
T运算符()(){
返回objref;
}
};
仅当
引用\u包装器
存储可调用文件时可用,而普通
bool
则不可用。使用lamdba作为谓词

也考虑使用一个普通的<代码> Boo.<代码>,如果该布尔值是在一个不同的线程中被修改的,它与您的条件变量正在等待的那个线程不同。


如果您真的想使用包装而不是lambda,那么可以编写一个简单的包装类,该类重载
操作符()
,并在调用时返回存储的布尔值

struct bool_wrapper
{
    bool_wrapper(bool& b) : b_(&b) {}
    bool *b_;

    bool operator()() const noexcept { return *b_; }
};
现在,您可以使用此类包装布尔值并将其传递给
条件变量::wait
as

c.wait(lock, bool_wrapper(b));

除了另一个答案,它很好地解释了问题所在,我想我或许能够解释你是如何得出错误的预期的

瞧,还有Boost Phoenix版本的
ref()
cref()
,令人惊讶的是,这两个版本的引用可以作为Phoenix懒散演员使用。也就是说:
phx::ref()
phx::cref()
是函子

这意味着您可以简单地使用

c.wait(lock, phx::cref(b));

因为你可能在过去的某个地方遇到过它。

好的,我理解。我现在已经扩展了这个问题(如果没有这样的事情,我会把你的问题标记为正确的)。如果对
b
的访问受锁保护,我就不需要
std::atomic\u bool
,对吧?@javidcf
reference\u wrapper
确实定义了一个隐式转换操作符,将其转换为
t&
,但这里的问题是
条件变量::wait
需要一个返回
bool
的空谓词,所以它将尝试调用您传递给它的任何内容,就好像它是可调用的一样。您需要的是一个包装器,它存储
T
,并提供一个
操作符()
,该操作符只返回相同的
T
。我不知道有这样的包装,而且听起来也不是很有用,是吗?你可以自己写一本。如果您要通过互斥锁保护对布尔值的访问,那么您不需要
原子\u bool
@javidcf添加了一个示例,但如果我是您,我会使用lambda。好的,谢谢,我理解。这并不是说我讨厌lambdas或其他东西,但我很好奇标准中是否已经包含了它。
std::ref
返回一个引用包装器。Boost Phoenix
ref
返回一个函子。我想你可能把两者混淆了(见我的答案)
,而(!b){c.wait(lock);}
c.wait(lock,[]{return b;})更可读一点,语义相同。当
b
是需要捕获的本地(
c.wait(lock,[&]{return b;});
)或成员变量(
c.wait(lock,[this]{return b;});
),但显式版本保持不变时,lambda就变得更糟糕了。哇,我从来没有听说过它,但实际上我就是这么想的。
c.wait(lock, phx::cref(b));