面试题答案
一键面试同步机制设计
-
同步原语选择
- 互斥锁(Mutex):用于保护共享数据,确保在同一时间只有一个线程能够访问这些数据。例如,当多个线程可能同时访问和修改类的某个成员变量时,在访问该变量前后加锁解锁。
- 条件变量(Condition Variable):用于线程间的通信和同步。当某个条件满足时,通过条件变量通知等待的线程。比如,在生产者 - 消费者模型中,当缓冲区有数据时,生产者线程通过条件变量通知消费者线程。
- 信号量(Semaphore):可以控制同时访问共享资源的线程数量。如果共享资源有一定的数量限制,例如数据库连接池的连接数量有限,就可以使用信号量来管理。
-
处理死锁问题
- 破坏死锁的四个必要条件:
- 互斥条件:无法完全破坏,因为共享数据必须互斥访问。
- 占有并等待条件:可以要求线程一次性获取所有需要的锁,而不是获取部分锁后再等待其他锁。例如,在进入某个关键代码段前,先获取所有相关的锁。
- 不可剥夺条件:当检测到死锁时,可以通过某种机制剥夺某个线程的锁资源,让其他线程能够继续执行。例如,在操作系统层面可以通过优先级等方式剥夺锁。
- 循环等待条件:对锁进行排序,要求线程按照固定顺序获取锁。例如,为所有锁分配一个唯一的ID,线程总是先获取ID小的锁,再获取ID大的锁。
- 死锁检测:定期检查线程的锁持有情况和等待状态,当发现有循环等待的情况时,采取相应措施,如终止某个线程或者释放部分锁资源。
- 破坏死锁的四个必要条件:
-
同步操作对整体性能的影响
- 积极影响:通过同步机制保证了数据一致性,避免了数据竞争导致的未定义行为和错误结果,提高了程序的稳定性和正确性。这在一些对数据准确性要求极高的场景,如金融计算等非常重要。
- 消极影响:同步操作会引入额外的开销,例如加锁解锁操作需要时间,可能导致线程上下文切换等。过多的同步操作会降低并行度,使程序的性能瓶颈出现在同步操作上,降低整体执行效率。
代码示例(以C++为例)
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
class SharedData {
public:
void addData(int value) {
std::unique_lock<std::mutex> lock(mutex_);
dataQueue.push(value);
lock.unlock();
condVar.notify_one();
}
bool getData(int& value) {
std::unique_lock<std::mutex> lock(mutex_);
condVar.wait(lock, [this] { return!dataQueue.empty(); });
if (dataQueue.empty()) {
return false;
}
value = dataQueue.front();
dataQueue.pop();
return true;
}
private:
std::queue<int> dataQueue;
std::mutex mutex_;
std::condition_variable condVar;
};
void producer(SharedData& sharedData) {
for (int i = 0; i < 10; ++i) {
sharedData.addData(i);
std::cout << "Produced: " << i << std::endl;
}
}
void consumer(SharedData& sharedData) {
int value;
while (true) {
if (sharedData.getData(value)) {
std::cout << "Consumed: " << value << std::endl;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
}
int main() {
SharedData sharedData;
std::thread producerThread(producer, std::ref(sharedData));
std::thread consumerThread(consumer, std::ref(sharedData));
producerThread.join();
consumerThread.join();
return 0;
}
在上述代码中:
SharedData
类包含一个队列dataQueue
用于存储数据,一个互斥锁mutex_
保护队列,一个条件变量condVar
用于线程间通信。addData
函数在向队列添加数据前加锁,添加完成后解锁并通知等待的线程。getData
函数使用条件变量等待队列有数据,获取数据前加锁,获取后解锁。producer
线程模拟生产者向共享数据添加数据,consumer
线程模拟消费者从共享数据获取数据。