面试题答案
一键面试1. 线程同步机制
- 互斥锁(Mutex):
- 使用互斥锁来保护对
InnerResource
的创建和销毁操作。当一个线程要创建或销毁InnerResource
时,先获取互斥锁,操作完成后释放互斥锁。这样可以保证同一时间只有一个线程能对InnerResource
进行创建或销毁操作,避免数据竞争。 - 在C++ 中,可以使用
std::mutex
来实现。例如:
- 使用互斥锁来保护对
#include <iostream>
#include <mutex>
#include <thread>
class InnerResource {
public:
InnerResource() { std::cout << "InnerResource created" << std::endl; }
~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};
class ThreadSafeOuter {
private:
InnerResource* innerResource;
std::mutex innerMutex;
public:
ThreadSafeOuter() : innerResource(nullptr) {}
~ThreadSafeOuter() {
std::lock_guard<std::mutex> lock(innerMutex);
if (innerResource) {
delete innerResource;
}
}
InnerResource* getInnerResource() {
std::lock_guard<std::mutex> lock(innerMutex);
if (!innerResource) {
innerResource = new InnerResource();
}
return innerResource;
}
};
void threadFunction(ThreadSafeOuter& outer) {
InnerResource* resource = outer.getInnerResource();
// 使用 resource 进行操作
}
int main() {
ThreadSafeOuter outer;
std::thread t1(threadFunction, std::ref(outer));
std::thread t2(threadFunction, std::ref(outer));
t1.join();
t2.join();
return 0;
}
- 读写锁(Read - Write Lock):
- 如果对
InnerResource
的操作主要是读多写少,可以使用读写锁。多个线程可以同时读取InnerResource
,但在写入(创建或销毁)时需要独占锁。在C++ 中,可以使用std::shared_mutex
来实现。例如:
- 如果对
#include <iostream>
#include <shared_mutex>
#include <thread>
class InnerResource {
public:
InnerResource() { std::cout << "InnerResource created" << std::endl; }
~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};
class ThreadSafeOuter {
private:
InnerResource* innerResource;
std::shared_mutex innerMutex;
public:
ThreadSafeOuter() : innerResource(nullptr) {}
~ThreadSafeOuter() {
std::unique_lock<std::shared_mutex> lock(innerMutex);
if (innerResource) {
delete innerResource;
}
}
InnerResource* getInnerResource() {
std::shared_lock<std::shared_mutex> lock(innerMutex);
if (!innerResource) {
lock.unlock();
std::unique_lock<std::shared_mutex> exclusiveLock(innerMutex);
if (!innerResource) {
innerResource = new InnerResource();
}
}
return innerResource;
}
};
void threadFunction(ThreadSafeOuter& outer) {
InnerResource* resource = outer.getInnerResource();
// 使用 resource 进行操作
}
int main() {
ThreadSafeOuter outer;
std::thread t1(threadFunction, std::ref(outer));
std::thread t2(threadFunction, std::ref(outer));
t1.join();
t2.join();
return 0;
}
2. 内存模型
- 顺序一致性(Sequential Consistency):
- 确保所有线程以相同的顺序看到对
InnerResource
的创建和销毁操作。在C++ 中,使用std::memory_order_seq_cst
内存序可以达到顺序一致性。例如,在std::atomic
类型变量的操作中使用该内存序。但在上述示例中,由于使用了std::mutex
,std::mutex
已经提供了足够的内存同步保证,使得对InnerResource
的操作在不同线程间具有顺序一致性。 - 例如,对于
InnerResource*
指针的更新,可以使用std::atomic<InnerResource*>
并结合std::memory_order_seq_cst
内存序来保证顺序一致性:
- 确保所有线程以相同的顺序看到对
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
class InnerResource {
public:
InnerResource() { std::cout << "InnerResource created" << std::endl; }
~InnerResource() { std::cout << "InnerResource destroyed" << std::endl; }
};
class ThreadSafeOuter {
private:
std::atomic<InnerResource*> innerResource;
std::mutex innerMutex;
public:
ThreadSafeOuter() : innerResource(nullptr) {}
~ThreadSafeOuter() {
std::lock_guard<std::mutex> lock(innerMutex);
InnerResource* res = innerResource.load(std::memory_order_seq_cst);
if (res) {
delete res;
}
}
InnerResource* getInnerResource() {
InnerResource* res = innerResource.load(std::memory_order_acquire);
if (!res) {
std::lock_guard<std::mutex> lock(innerMutex);
res = innerResource.load(std::memory_order_relaxed);
if (!res) {
InnerResource* newRes = new InnerResource();
innerResource.store(newRes, std::memory_order_release);
res = newRes;
}
}
return res;
}
};
void threadFunction(ThreadSafeOuter& outer) {
InnerResource* resource = outer.getInnerResource();
// 使用 resource 进行操作
}
int main() {
ThreadSafeOuter outer;
std::thread t1(threadFunction, std::ref(outer));
std::thread t2(threadFunction, std::ref(outer));
t1.join();
t2.join();
return 0;
}
通过上述线程同步机制(互斥锁、读写锁等)和内存模型(顺序一致性等)的结合使用,可以保证 InnerResource
的作用域和生命周期在多线程竞争条件下的正确性,避免数据竞争和未定义行为。