C++ 什么';一般来说,处理虚假唤醒的正确方法是什么?
在下面的选项中,当使用条件变量时,有没有正确的方法来处理虚假唤醒 1) 将C++ 什么';一般来说,处理虚假唤醒的正确方法是什么?,c++,c++11,condition-variable,spurious-wakeup,C++,C++11,Condition Variable,Spurious Wakeup,在下面的选项中,当使用条件变量时,有没有正确的方法来处理虚假唤醒 1) 将wait(unique_lock_ul)放入无限while循环,使用布尔值 unique_lock<mutex> ul(m); while(!full) cv.wait(ul); 如果这些都不正确,那么如何轻松处理虚假唤醒 我对C++中的条件变量很陌生,我不确定我读的一些代码是否处理了虚假唤醒的问题。 < P>简短的答案是,您的代码可能是正确的或错误的;您没有确切显示完整的是如何操作的 C++代码的各
wait(unique_lock_ul)
放入无限while
循环,使用布尔值
unique_lock<mutex> ul(m);
while(!full)
cv.wait(ul);
如果这些都不正确,那么如何轻松处理虚假唤醒
我对C++中的条件变量很陌生,我不确定我读的一些代码是否处理了虚假唤醒的问题。 < P>简短的答案是,您的代码可能是正确的或错误的;您没有确切显示
完整的是如何操作的
<> C++代码的各个位从来都不是线程安全的。线程安全是代码的一个关系属性;如果两位代码永远不会导致竞争条件,那么它们彼此之间可以是线程安全的
但是一位代码永远不会是线程安全的;说某物是线程安全的就像说某物是“相同的高度”
“猴子见猴子做”条件变量模式如下:
template<class T>
class cv_bundle {
std::mutex m;
T payload;
std::condition_variable cv;
public:
explicit cv_bundle( T in ):payload(std::move(in)) {}
template<class Test, class Extract>
auto wait( Test&& test, Extract&& extract ) {
std::unique_lock<std::mutex> l(m);
cv.wait( l, [&]{ return test(payload); } );
return extract(payload);
}
template<class Setter>
void load( Setter&& setter, bool only_one = true ) {
std::unique_lock<std::mutex> l(m);
bool is_set = setter( payload );
if (!is_set) return; // nothing to notify
if (only_one)
cv.notify_one();
else
cv.notify_all();
}
};
模板
类cv_束{
std::互斥m;
T有效载荷;
std::条件变量cv;
公众:
显式cv_bundle(tin):有效负载(std::move(in)){
模板
自动等待(测试和测试、提取和提取){
std::唯一锁l(m);
等待(l,[&]{返回测试(有效载荷);});
返回提取(有效载荷);
}
模板
无效加载(Setter&&Setter,bool only\u one=true){
std::唯一锁l(m);
bool is_set=设定器(有效载荷);
如果(!is_set)return;//没有要通知的内容
如果(只有一个)
cv.通知_one();
其他的
cv.通知所有人();
}
};
test
接受一个T&payload
,如果有东西要消耗,则返回true(即,唤醒不是虚假的)
extract
获取T&payload
并从中返回您想要的任何信息。它通常应该重置有效载荷
setter
修改T&payload
,使test
返回true
。如果这样做,则返回true
。如果选择不执行,则返回false
所有3个都在对T有效负载的互斥锁访问中被调用
现在,您可以在此基础上生成变体,但这样做很难正确。例如,不要假设原子负载意味着不必锁定互斥锁
当我将这三件事捆绑在一起时,您可以对一堆条件变量使用一个互斥体,或者对不仅仅是条件变量使用互斥体。有效载荷可以是一个布尔、一个计数器、一个数据向量,或者其他更为陌生的东西;通常,它必须始终受到互斥的保护。如果它是原子的,则在修改的值和通知之间的打开间隔的某个时间点,必须锁定互斥锁,否则可能会丢失通知
手动循环控制而不是传递lambda是一种修改,但是描述哪种手动循环是合法的,哪种是竞争条件是一个复杂的问题
实际上,除非我有非常好的理由,否则我不会让这个猴子看到猴子做“货物崇拜”式的条件变量的使用。然后我不得不阅读C++内存和线程模型,这不能成为我的一天,这意味着我的代码很可能不正确。
请注意,如果传入的任何lambda进入并回调到cv_bundle
中,我显示的代码将不再有效。1或3种方式都可以处理虚假唤醒(假设完全修改受同一互斥锁保护),除非谓词条件错误,否则应该是:
unique_lock<mutex> ul(m);
cv.wait(ul, [&](){return full;});
唯一锁定ul(m);
cv.wait(ul,[&](){returnfull;});
使此代码等于变量1
与其他两种情况不同,变型2不正常,但不会重新检查伪唤醒等待条件。1)
和2)
是相同的代码。你是想展示一些不同的东西吗?是的,对不起,我刚修改过
template<class T>
class cv_bundle {
std::mutex m;
T payload;
std::condition_variable cv;
public:
explicit cv_bundle( T in ):payload(std::move(in)) {}
template<class Test, class Extract>
auto wait( Test&& test, Extract&& extract ) {
std::unique_lock<std::mutex> l(m);
cv.wait( l, [&]{ return test(payload); } );
return extract(payload);
}
template<class Setter>
void load( Setter&& setter, bool only_one = true ) {
std::unique_lock<std::mutex> l(m);
bool is_set = setter( payload );
if (!is_set) return; // nothing to notify
if (only_one)
cv.notify_one();
else
cv.notify_all();
}
};
unique_lock<mutex> ul(m);
cv.wait(ul, [&](){return full;});