我正在调试一些线程代码,我遇到了一些我不理解的行为。
我创建了一个线程向量。我有变量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
(除主线程外)。
答案 0 :(得分:3)
每个线程线程在计数器不为零的条件下等待
这实际上不是你的条件:
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()