面试题答案
一键面试假设示例代码
#include <iostream>
#include <thread>
#include <mutex>
int sharedResource = 0;
std::mutex resourceMutex;
void increment() {
for (int i = 0; i < 1000; ++i) {
// 这里缺少对共享资源访问的保护
sharedResource++;
}
}
void decrement() {
for (int i = 0; i < 1000; ++i) {
// 这里缺少对共享资源访问的保护
sharedResource--;
}
}
int main() {
std::thread thread1(increment);
std::thread thread2(decrement);
thread1.join();
thread2.join();
std::cout << "Final value of sharedResource: " << sharedResource << std::endl;
return 0;
}
可能导致崩溃的原因
- 竞态条件(Race Condition):多个线程同时访问和修改
sharedResource
这个共享资源,而没有适当的同步机制。这会导致数据竞争,使得sharedResource
的值可能被错误地修改,进而可能导致程序崩溃。例如,一个线程读取sharedResource
的值,另一个线程同时修改了该值,第一个线程基于旧值进行的后续操作就可能产生错误。
正确的修复方案
- 使用互斥锁(Mutex):在访问共享资源前锁定互斥锁,访问完成后解锁互斥锁。修改后的代码如下:
#include <iostream>
#include <thread>
#include <mutex>
int sharedResource = 0;
std::mutex resourceMutex;
void increment() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<std::mutex> lock(resourceMutex);
sharedResource++;
}
}
void decrement() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<std::mutex> lock(resourceMutex);
sharedResource--;
}
}
int main() {
std::thread thread1(increment);
std::thread thread2(decrement);
thread1.join();
thread2.join();
std::cout << "Final value of sharedResource: " << sharedResource << std::endl;
return 0;
}
std::lock_guard
是一个 RAII(Resource Acquisition Is Initialization) 类,在构造时自动锁定互斥锁,在析构时自动解锁互斥锁,确保了在访问共享资源时的线程安全。
- 使用其他同步机制:除了互斥锁,还可以使用
std::unique_lock
来获得更灵活的锁控制,或者使用std::condition_variable
来实现线程间的条件同步,不过对于这个简单的示例,std::lock_guard
配合std::mutex
已经足够。