见下面的代码,
AsyncTask
创建一个对等线程(定时器)来增加一个原子变量并休眠一段时间。预期的输出是打印10次counter_
,取值范围为1到10,但实际结果很奇怪:
#include <atomic>
#include <thread>
#include <iostream>
class AtomicTest {
public:
int AsyncTask() {
std::thread timer([this](){
while (not stop_.load(std::memory_order_acquire)) {
counter_.fetch_add(1, std::memory_order_relaxed);
std::cout << "counter = " << counter_ << std::endl;
std::this_thread::sleep_for(std::chrono::microseconds(1)); // both milliseconds and seconds work well
}
});
timer.detach();
std::this_thread::sleep_for(std::chrono::microseconds(10));
stop_.store(true, std::memory_order_release);
return 0;
}
private:
std::atomic<int> counter_{0};
std::atomic<bool> stop_{false};
};
int main(void) {
AtomicTest test;
test.AsyncTask();
return 0;
}
我知道线程切换也是需要时间的,难道是线程休眠时间太短了?
我的程序运行环境:
是的,
stop_.store
可以在新线程被调度到 CPU 内核之前或之后运行,这是很容易理解的。所以它的第一个测试将停止标志读取为true
.
10 us 比典型的操作系统进程调度时间片(通常为 1 或 10 毫秒)短,以防相关。对于原子存储变得可见,只比内核间延迟高几个数量级。
你描述的结果正是我对像这样的依赖于时间的程序的期望,编写它是为了检测哪个线程赢得了比赛以及赢得了多少(它的速度慢
<< endl
并在写入线程内休眠。)
我绝对不希望它总是打印 10 次,而且由于线程启动开销占打印线程内 1 us 睡眠间隔的很大一部分,这种情况很少发生。