面试题答案
一键面试可能出现的问题
- 数据竞争:多个线程同时访问和修改被观察对象(Subject)或观察者(Observer)的状态,导致数据不一致。例如,一个线程在更新被观察对象的状态,而另一个线程同时在通知观察者,可能会导致观察者接收到不一致的数据。
- 竞态条件:不同线程执行顺序的不确定性可能导致竞态条件。比如,一个线程在注册观察者时,另一个线程可能正在通知观察者,可能导致部分观察者没有接收到通知。
- 死锁:如果在加锁过程中顺序不当,可能会产生死锁。例如,线程A持有锁L1并尝试获取锁L2,而线程B持有锁L2并尝试获取锁L1,就会导致死锁。
优化方案
- 使用互斥锁(Mutex):在访问共享数据(如被观察对象的状态和观察者列表)时加锁,以确保同一时间只有一个线程可以访问。
- 读写锁(Read - Write Lock):如果读操作远多于写操作,可以使用读写锁。读操作时允许多个线程同时进行,写操作时则独占锁,防止其他读写操作。
- 条件变量(Condition Variable):用于线程间的同步,例如当被观察对象状态改变时,通过条件变量通知等待的观察者线程。
代码示例
#include <iostream>
#include <vector>
#include <memory>
#include <mutex>
#include <thread>
#include <condition_variable>
class Observer;
class Subject {
public:
void attach(std::shared_ptr<Observer> observer);
void detach(std::shared_ptr<Observer> observer);
void notify();
void setState(int state);
int getState() const;
private:
std::vector<std::shared_ptr<Observer>> observers;
int state;
std::mutex mtx;
std::condition_variable cv;
};
class Observer {
public:
virtual void update(const Subject& subject) = 0;
};
void Subject::attach(std::shared_ptr<Observer> observer) {
std::lock_guard<std::mutex> lock(mtx);
observers.push_back(observer);
}
void Subject::detach(std::shared_ptr<Observer> observer) {
std::lock_guard<std::mutex> lock(mtx);
auto it = std::find(observers.begin(), observers.end(), observer);
if (it != observers.end()) {
observers.erase(it);
}
}
void Subject::notify() {
std::unique_lock<std::mutex> lock(mtx);
for (const auto& observer : observers) {
observer->update(*this);
}
cv.notify_all();
}
void Subject::setState(int state) {
std::lock_guard<std::mutex> lock(mtx);
this->state = state;
notify();
}
int Subject::getState() const {
std::lock_guard<std::mutex> lock(mtx);
return state;
}
class ConcreteObserver : public Observer {
public:
void update(const Subject& subject) override {
std::cout << "Observer notified. Subject state: " << subject.getState() << std::endl;
}
};
void threadFunction(std::shared_ptr<Subject> subject) {
std::unique_lock<std::mutex> lock(subject->mtx);
subject->cv.wait(lock, [&subject] { return subject->getState() != 0; });
std::cout << "Thread awakened. Subject state: " << subject->getState() << std::endl;
}
int main() {
auto subject = std::make_shared<Subject>();
auto observer1 = std::make_shared<ConcreteObserver>();
auto observer2 = std::make_shared<ConcreteObserver>();
subject->attach(observer1);
subject->attach(observer2);
std::thread t1(threadFunction, subject);
subject->setState(42);
t1.join();
subject->detach(observer1);
subject->detach(observer2);
return 0;
}
在这个示例中:
Subject
类使用std::mutex
来保护observers
列表和state
变量。attach
和detach
方法在修改observers
列表时加锁。notify
方法在通知观察者时加锁,并使用std::condition_variable
通知等待的线程。setState
方法在更新状态后调用notify
方法。- 线程函数
threadFunction
通过std::condition_variable
等待Subject
状态的改变。