C++ 使用引用包装器作为条件变量谓词
注意:以下内容同样适用于Boost.Thread和C++11线程 我有一个条件变量,这个条件实际上是一个简单的布尔变量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
// 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
,对吧?@javidcfreference\u wrapper
确实定义了一个隐式转换操作符,将其转换为t&
,但这里的问题是条件变量::wait
需要一个返回bool
的空谓词,所以它将尝试调用您传递给它的任何内容,就好像它是可调用的一样。您需要的是一个包装器,它存储T
,并提供一个操作符()
,该操作符只返回相同的T
。我不知道有这样的包装,而且听起来也不是很有用,是吗?你可以自己写一本。如果您要通过互斥锁保护对布尔值的访问,那么您不需要原子\u bool
@javidcf添加了一个示例,但如果我是您,我会使用lambda。好的,谢谢,我理解。这并不是说我讨厌lambdas或其他东西,但我很好奇标准中是否已经包含了它。std::ref
返回一个引用包装器。Boost Phoenixref
返回一个函子。我想你可能把两者混淆了(见我的答案),而(!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));