面试题答案
一键面试可能面临的挑战
- 竞态条件:多个线程同时调用
++
运算符时,由于对内部计数器的读取、增加和写入操作不是原子的,可能导致最终结果不准确。 - 死锁:如果在使用互斥锁等同步机制时,加锁顺序不当或者锁的嵌套使用不合理,可能会导致死锁。
解决方案
- 使用互斥锁:在
++
运算符重载函数中使用互斥锁来保护对内部计数器的操作。在进入函数时加锁,操作完成后解锁。 - 原子操作:C++ 标准库提供了
std::atomic
类型,对于简单的计数器操作,可以直接使用std::atomic
类型来代替普通类型,从而保证操作的原子性,无需额外的锁机制。
代码示例
- 使用互斥锁
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
class SharedClass {
private:
int counter;
std::mutex mtx;
public:
SharedClass() : counter(0) {}
SharedClass& operator++() {
std::lock_guard<std::mutex> lock(mtx);
++counter;
return *this;
}
int getCounter() const {
std::lock_guard<std::mutex> lock(mtx);
return counter;
}
};
void increment(SharedClass& sharedObj) {
for (int i = 0; i < 1000; ++i) {
++sharedObj;
}
}
int main() {
SharedClass sharedObj;
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, std::ref(sharedObj));
}
for (auto& thread : threads) {
thread.join();
}
std::cout << "Final counter value: " << sharedObj.getCounter() << std::endl;
return 0;
}
- 使用原子操作
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
class SharedClass {
private:
std::atomic<int> counter;
public:
SharedClass() : counter(0) {}
SharedClass& operator++() {
++counter;
return *this;
}
int getCounter() const {
return counter.load();
}
};
void increment(SharedClass& sharedObj) {
for (int i = 0; i < 1000; ++i) {
++sharedObj;
}
}
int main() {
SharedClass sharedObj;
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i) {
threads.emplace_back(increment, std::ref(sharedObj));
}
for (auto& thread : threads) {
thread.join();
}
std::cout << "Final counter value: " << sharedObj.getCounter() << std::endl;
return 0;
}
以上两种方案都能解决多线程环境下 ++
运算符重载的正确性问题,使用原子操作通常在性能上更优,因为避免了锁的开销。但对于更复杂的操作,可能还是需要结合互斥锁等同步机制。