MST

星途 面试题库

面试题:C++中观察者模式在多线程环境下的优化

在C++中,当使用观察者模式时,如果处于多线程环境,可能会出现哪些问题?请详细说明,并给出优化方案及相应的代码示例。
17.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

可能出现的问题

  1. 数据竞争:多个线程同时访问和修改被观察对象(Subject)或观察者(Observer)的状态,导致数据不一致。例如,一个线程在更新被观察对象的状态,而另一个线程同时在通知观察者,可能会导致观察者接收到不一致的数据。
  2. 竞态条件:不同线程执行顺序的不确定性可能导致竞态条件。比如,一个线程在注册观察者时,另一个线程可能正在通知观察者,可能导致部分观察者没有接收到通知。
  3. 死锁:如果在加锁过程中顺序不当,可能会产生死锁。例如,线程A持有锁L1并尝试获取锁L2,而线程B持有锁L2并尝试获取锁L1,就会导致死锁。

优化方案

  1. 使用互斥锁(Mutex):在访问共享数据(如被观察对象的状态和观察者列表)时加锁,以确保同一时间只有一个线程可以访问。
  2. 读写锁(Read - Write Lock):如果读操作远多于写操作,可以使用读写锁。读操作时允许多个线程同时进行,写操作时则独占锁,防止其他读写操作。
  3. 条件变量(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;
}

在这个示例中:

  1. Subject类使用std::mutex来保护observers列表和state变量。
  2. attachdetach方法在修改observers列表时加锁。
  3. notify方法在通知观察者时加锁,并使用std::condition_variable通知等待的线程。
  4. setState方法在更新状态后调用notify方法。
  5. 线程函数threadFunction通过std::condition_variable等待Subject状态的改变。