【C/C++】Observer与Producer-Consumer模式解析

Observer Pattern

The Observer Pattern is a behavioral design pattern used to allow an object (called the subject ) to notify a list of observers when its state changes. The pattern defines a one-to-many relationship between objects. When the subject changes, all registered observers are automatically notified.

Key Components:
  • Subject: The object that maintains a list of observers. It notifies the observers when its state changes.
  • Observer : An interface or abstract class that defines the update method. Concrete observers implement this method to react to changes in the subject.
  • ConcreteSubject: A subclass of the subject, which has the state being tracked and notifies observers when the state changes.
  • ConcreteObserver: A concrete class that implements the observer interface to react to changes in the subject.
Use Case:

The Observer Pattern is often used when multiple objects need to react to changes in the state of another object. For example, UI frameworks use the observer pattern to update the display when the underlying data changes.

Synchronization in Observer Pattern:

The Observer pattern can be used in both synchronous and asynchronous environments. The key aspect of the pattern is the notification of observers, which can be synchronous or asynchronous depending on how the update method is invoked.

  • Synchronous : In a basic implementation, when the subject's state changes, it calls the update method of all its observers synchronously. The observers will execute in the same thread as the subject.

  • Asynchronous: In more advanced implementations, observers may be notified asynchronously, often using queues, background threads, or events to trigger the observers' updates.

Producer-Consumer Pattern

The Producer-Consumer Pattern is a concurrency pattern used to decouple tasks by using a buffer between producers and consumers. The producer is responsible for producing data (e.g., producing items, events, or tasks), while the consumer processes or consumes that data. The buffer, often implemented as a queue, holds the data temporarily until the consumer can process it.

Key Components:
  • Producer: An entity that creates data and adds it to the buffer.
  • Consumer: An entity that removes data from the buffer and processes it.
  • Buffer (Queue): A shared resource (typically a queue) that holds the data between the producer and the consumer. It can be implemented in various ways, such as using a thread-safe queue.
Use Case:

The Producer-Consumer pattern is commonly used in systems where one or more producers generate tasks (or data) that need to be consumed by one or more consumers. Examples include:

  • Task scheduling in a multi-threaded environment.
  • Web server request processing.
  • Data streaming or logging systems.
Asynchronous Nature of Producer-Consumer:

In the Producer-Consumer pattern, operations are typically asynchronous. Here's why:

  • Producers can create data at different rates from the consumers. The producer might be slower or faster than the consumer, and the buffer can store the produced data temporarily.
  • Consumers process data from the buffer asynchronously, which can involve waiting for data or consuming data as it arrives. They don't block the producer and can process data in parallel with it.

Key Differences and When to Use Them

  • Observer Pattern is primarily about notifying and updating. It's most commonly used to update different components when a change occurs in the subject. Observers can be registered to listen for changes in a subject and respond to those changes, often used for UI updates, event handling, and notifications.

  • Producer-Consumer Pattern is focused on asynchronous task management. It decouples data production and consumption, typically used to handle tasks concurrently or to ensure that the producer and consumer don't overwhelm each other, especially when data arrives at unpredictable rates.

Are They Used in Sync or Async?
  • Observer Pattern can be both synchronous and asynchronous. In synchronous cases, all observers are notified in the same thread as the subject's change. In asynchronous cases, observers can be notified on separate threads or events can be queued for later execution.

  • Producer-Consumer Pattern is typically asynchronous because it's designed for handling tasks concurrently. The producer and consumer don't operate at the same rate, and the queue acts as a buffer to prevent the producer from overwhelming the consumer or vice versa.

Example Code in C++

Observer Pattern Example (Synchronous):
cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

// Observer Interface
class Observer {
public:
    virtual void update(const std::string& message) = 0;
};

// Concrete Observer
class ConcreteObserver : public Observer {
public:
    void update(const std::string& message) override {
        std::cout << "Observer received: " << message << std::endl;
    }
};

// Subject Class
class Subject {
private:
    std::vector<Observer*> observers;

public:
    void addObserver(Observer* observer) {
        observers.push_back(observer);
    }

    void removeObserver(Observer* observer) {
        observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
    }

    void notifyObservers(const std::string& message) {
        for (auto& observer : observers) {
            observer->update(message);
        }
    }
};

int main() {
    Subject subject;
    ConcreteObserver observer1, observer2;
    subject.addObserver(&observer1);
    subject.addObserver(&observer2);
    
    subject.notifyObservers("Hello Observers!");
    return 0;
}
Producer-Consumer Pattern Example (Asynchronous):
cpp 复制代码
#include <iostream>
#include <thread>
#include <queue>
#include <condition_variable>
#include <atomic>

// Shared Queue and Sync Mechanism
std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv;
std::atomic<bool> done(false);

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        std::lock_guard<std::mutex> lock(mtx);
        buffer.push(i);
        std::cout << "Produced: " << i << std::endl;
        cv.notify_all();  // Notify consumers
    }
    done = true;
    cv.notify_all();  // Notify consumer to exit
}

void consumer() {
    while (!done || !buffer.empty()) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !buffer.empty() || done; });  // Wait for data to consume

        if (!buffer.empty()) {
            int data = buffer.front();
            buffer.pop();
            std::cout << "Consumed: " << data << std::endl;
        }
    }
}

int main() {
    std::thread prod(producer);
    std::thread cons(consumer);

    prod.join();
    cons.join();

    return 0;
}

Conclusion:

  • Observer Pattern is about keeping components in sync by notifying them when a change occurs, and it can be both synchronous and asynchronous.
  • Producer-Consumer Pattern is designed for decoupling tasks and is inherently asynchronous, where producers and consumers work in parallel, potentially at different rates, with a shared buffer.

Both patterns serve different purposes: Observer handles event notification and synchronization between components, while Producer-Consumer helps manage concurrency and task flow, typically for performance and load balancing.

相关推荐
HaiQinyanAN1 分钟前
【学习笔记】重载和重写的注意事项
c++·笔记·学习
梦境虽美,却不长19 分钟前
C语言 学习 文件操作(开关,读写,定位,大小)操作 2025年6月8日12:19:24
c语言·开发语言·学习
Charlotte_jc28 分钟前
完美解决openpyxl保存Excel丢失图像/形状资源的技术方案
开发语言·python·excel·openpyxl
西北大程序猿1 小时前
服务器代码知识点补充
服务器·开发语言·网络·c++·网络协议
打不了嗝 ᥬ᭄2 小时前
进程控制
linux·运维·服务器·c++
新知图书3 小时前
R语言ICU患者死亡率预测实战
开发语言·r语言
yxc_inspire3 小时前
基于Qt的app开发第十四天
前端·c++·qt·app·面向对象·qss
wennieFan3 小时前
python基础面试练习题
开发语言·python
阿福不是狗3 小时前
Python使用总结之Linux部署python3环境
linux·开发语言·python
枣伊吕波3 小时前
第十三节:第七部分:Stream流的中间方法、Stream流的终结方法
java·开发语言