面试题答案
一键面试设计思路
- 保证线程安全:
- 使用互斥锁(
std::mutex
)对容器的访问和修改进行保护。在访问或修改容器前锁定互斥锁,操作完成后解锁。 - 考虑使用读写锁(
std::shared_mutex
),如果读取操作远多于写入操作,读操作时可以多个线程同时进行,提高并发性能。
- 使用互斥锁(
- 处理迭代器失效问题:
- 在每次使用迭代器前,检查其有效性。可以通过保存容器的大小,在使用迭代器时对比当前容器大小是否改变来判断迭代器是否失效。
- 当迭代器失效时,重新获取迭代器。例如,在修改容器后,重新调用
begin()
和end()
获取新的迭代器。
- 优化性能:
- 减少锁的粒度,尽量缩小锁定互斥锁的代码块范围,减少线程等待时间。
- 使用无锁数据结构替代 STL 容器,如果应用场景允许。例如,使用
boost::lockfree
库中的无锁队列等数据结构。
多线程代码示例
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <shared_mutex>
std::vector<int> data;
std::shared_mutex dataMutex;
void writeData(int value) {
std::unique_lock<std::shared_mutex> lock(dataMutex);
data.push_back(value);
}
void readData() {
std::shared_lock<std::shared_mutex> lock(dataMutex);
auto oldSize = data.size();
for (auto it = data.begin(); it != data.end(); ++it) {
if (data.size() != oldSize) {
// 迭代器失效,重新获取
lock.unlock();
std::unique_lock<std::shared_mutex> newLock(dataMutex);
it = data.begin();
oldSize = data.size();
newLock.unlock();
lock.lock();
}
std::cout << *it << " ";
}
std::cout << std::endl;
}
int main() {
std::thread writer1(writeData, 1);
std::thread writer2(writeData, 2);
std::thread reader1(readData);
std::thread reader2(readData);
writer1.join();
writer2.join();
reader1.join();
reader2.join();
return 0;
}
在上述代码中:
writeData
函数用于向data
容器中写入数据,使用std::unique_lock
锁定dataMutex
以保证线程安全。readData
函数用于读取data
容器中的数据,使用std::shared_lock
锁定dataMutex
以允许多个线程同时读取。在读取过程中,通过对比容器大小来检查迭代器是否失效,若失效则重新获取迭代器。main
函数中创建了两个写入线程和两个读取线程,展示了多线程环境下对data
容器的并发访问。