面试题答案
一键面试可能原因分析
- 缓存一致性问题:现代CPU为提高性能,每个核心都有自己的缓存。线程A修改标志位后,该修改可能只存在于其所在核心的缓存中,未及时刷新到主存,导致线程B从主存读取标志位时,读到的还是旧值。
- 编译器优化:编译器可能对代码进行优化,将标志位的读取操作优化到循环外部,从而导致线程B检测不到标志位的变化。
使用std::atomic
解决问题
std::atomic
提供了原子操作,保证对其变量的读写操作是原子性的,并且可以通过指定内存顺序来解决缓存一致性和编译器优化带来的问题。
代码示例
#include <iostream>
#include <thread>
#include <atomic>
#include <chrono>
std::atomic<bool> flag(false);
void threadA() {
// 模拟向网络发送数据
std::this_thread::sleep_for(std::chrono::seconds(1));
flag.store(true, std::memory_order_release);
}
void threadB() {
while (!flag.load(std::memory_order_acquire)) {
std::this_thread::yield();
}
// 后续数据处理
std::cout << "Thread B detected flag change and start processing." << std::endl;
}
int main() {
std::thread t1(threadA);
std::thread t2(threadB);
t1.join();
t2.join();
return 0;
}
在上述代码中:
std::atomic<bool> flag(false);
定义了一个原子类型的标志位flag
。flag.store(true, std::memory_order_release);
在线程A中使用store
方法设置标志位为true
,并使用std::memory_order_release
内存顺序,保证在此之前的写操作对其他线程可见。while (!flag.load(std::memory_order_acquire)) { }
在线程B中使用load
方法读取标志位,并使用std::memory_order_acquire
内存顺序,保证在此之后的读操作能看到之前线程A的写操作。