面试题答案
一键面试可能引发的问题
- 数据竞争(Data Race):多个线程同时访问和修改全局变量,导致结果不可预测。例如:
#include <iostream>
#include <thread>
int globalVar = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
globalVar++;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Expected: 20000, Actual: " << globalVar << std::endl;
return 0;
}
在上述代码中,两个线程同时对 globalVar
进行自增操作,由于自增操作不是原子的,可能会出现数据竞争,导致最终 globalVar
的值不一定是 20000。
- 线程安全问题:全局变量在不同线程间共享,可能被意外修改,破坏程序的逻辑。比如一个线程依赖全局变量的初始状态进行计算,但另一个线程在其计算过程中修改了该全局变量。
解决方法
- 使用互斥锁(Mutex):
#include <iostream>
#include <thread>
#include <mutex>
std::mutex globalMutex;
int globalVar = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(globalMutex);
globalVar++;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Expected: 20000, Actual: " << globalVar << std::endl;
return 0;
}
这里通过 std::mutex
和 std::lock_guard
来保护对 globalVar
的访问,确保同一时间只有一个线程能修改 globalVar
,从而避免数据竞争。
- 使用原子变量(Atomic Variables):C++11 引入了原子类型,对原子类型的操作是原子的,不会产生数据竞争。例如:
#include <iostream>
#include <thread>
#include <atomic>
std::atomic<int> globalVar(0);
void increment() {
for (int i = 0; i < 10000; ++i) {
globalVar++;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Expected: 20000, Actual: " << globalVar << std::endl;
return 0;
}
std::atomic<int>
类型的 globalVar
保证了自增操作的原子性,避免了数据竞争问题。