为什么只有一个锁和一个原子计数器的条件变量会错误地唤醒
Why does the condition variable wake up erroneously with only one lock and an atomic counter?
我正在调试一些线程代码,遇到了一些我不理解的行为。
我创建了一个线程向量。我有变量atomic_uint
Counter
和atomic_bool
Stop
,告诉线程何时应该停止。每个线程线程在计数器不为零的条件下等待,然后递减
在主线程中,我递增Counter
,并在此条件下调用notify_one()
。代码如下。
#include <thread>
#include <condition_variable>
#include <atomic>
#include <vector>
#include <iostream>
#include <cstdlib>
#include <mutex>
int main() {
const std::size_t Tasks = 100u;
const std::size_t Repetitions = 100u;
const std::size_t Threads = 4u;
std::mutex Mutex;
std::condition_variable Condition;
std::atomic_uint Counter(0);
std::atomic_uint MainCounter(0);
std::atomic_uint ThreadCounter(0);
std::atomic_bool Stop( false );
std::vector<std::thread> v;
for ( std::size_t i = 0; i < Threads; i++ ) {
v.emplace_back( [&ThreadCounter,&Mutex, &Condition, &Counter, &Stop]() -> void {
while ( true ) {
{
std::unique_lock<std::mutex> lock( Mutex );
Condition.wait( lock, [&Counter, &Stop]() -> bool {
//wait while this is false
return Counter.load() >= 0u || Stop;
} );
if ( Stop && Counter == 0u ) {
return;
}
ThreadCounter++;
if ( Counter == 0 ) {
continue;
}
Counter--;
}
} //while
});
} //for
for ( std::size_t i = 0u; i < Tasks; i++ ) {
MainCounter++;
Counter++;
Condition.notify_one();
}
while ( Counter != 0u ) {
std::this_thread::yield();
}
Stop = true;
Condition.notify_all();
for ( auto& t: v ) {
t.join();
}
std::cout << "ThreadCounter = " << ThreadCounter.load() << std::endl;
std::cout << "MainCounter = " << MainCounter.load() << std::endl;
return 0;
}
在线程代码中,我有一个额外的原子ThreadCounter
,用来跟踪Counter
实际减少了多少次。
ThreadCounter
的增量总是比调用Condition.notify_one()
的次数多得多:
ThreadCounter = 212
MainCounter = 100
当我用一把锁锁定条件时,这是如何发生的?据我所知,一次只有一个线程可以访问Counter
(除了主线程)。
每个线程线程在计数器不是零的条件下等待
这实际上不是你的情况:
Condition.wait( lock, [&Counter, &Stop]() -> bool {
//wait while this is false
return Counter.load() >= 0u || Stop;
// ^^^^^^^^^^^^^^^^^^^^
} );
Counter
是无符号的,所以>= 0u
总是真的。如果是Counter == 0
,那么循环体可能会多次增加ThreadCounter
,因此会出现差异。
你的意思可能是:
return Counter > 0 || Stop;
(您不需要在那里调用.load()
)
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 在没有太多条件句的情况下,我如何避免被零除
- 基于多个条件处理地图中的所有元素
- 条件constexpr函数
- 无论条件是否为true,if总是在c++中执行
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 基于模板值的条件变量
- 循环在计数器中不起作用
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 将按位if条件转换为普通if条件
- 条件断点在不应该触发时触发
- python集合的C++等价物是什么.计数器
- 为什么简单的算术减法在"if"条件下不起作用?
- 如何在for循环中包含两个索引值的测试条件
- 如何编写条件计数器
- 递减原子计数器 - 但在<only>一定条件下
- 为什么只有一个锁和一个原子计数器的条件变量会错误地唤醒
- 避免在增加计数器时出现争用条件
- 使用 for 循环中的计数器作为条件
- 计数器根据循环内的两种不同条件更新