首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

muduo 庫源碼剖析 (一):Reactor 模式與 EventLoop、Channel、Poller 三大核心組件

     編輯:關於C++

Reactor 模式核心思想

Reactor (反應堆) 是事件驅動架構的基石:**控制反轉**。傳統同步阻塞調用:應用主動呼叫 API 等待完成。Reactor 模式:應用註冊回調函數 (Handler) 到 Reactor,當事件發生時,Reactor **主動回調** 應用註冊的處理函數。

傳統模式:          Reactor 模式:
App → read()       App → registerHandler(fd, callback)
    ↓ 阻塞等待           ↓ 立即返回
    ↓ 內核處理           Reactor → poll()/epoll_wait()
    ↓ 返回資料           事件就緒 → callback(data)
    處理資料

muduo 三大核心類

EventLoop:每個線程一個事件循環

class EventLoop : noncopyable {
public:
    using Functor = std::function;
    
    EventLoop();  // 綁定當前線程 threadId_
    ~EventLoop();
    
    void loop();                    // 啟動事件循環
    void quit();                    // 退出循環
    
    // 跨線程任務提交
    void runInLoop(Functor cb);     // 當前線程直接執行,其他線程進 queueInLoop
    void queueInLoop(Functor cb);   // 線程安全加入 pendingFunctors_
    
    // 定時器
    TimerId runAt(Timestamp, Functor);
    TimerId runAfter(double delay, Functor);
    TimerId runEvery(double interval, Functor);
    
    // Channel 管理 (供 Channel 調用)
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    bool hasChannel(Channel* channel);
    
    // 喚醒機制 (跨線程通知)
    void wakeup();                  // 向 eventfd 寫入 1
    
private:
    void doPendingFunctors();       // 執行所有排隊任務
    void handleRead();              // eventfd 讀回調,消費 wakeup 數據
    
    const pid_t threadId_;          // 綁定線程 ID
    std::unique_ptr poller_;
    std::unique_ptr timerQueue_;
    int wakeupFd_;                  // eventfd
    std::unique_ptr wakeupChannel_;  // 監聽 wakeupFd 讀事件
    ChannelList activeChannels_;    // 就緒 Channel 列表
    Channel* currentActiveChannel_; // 當前處理的 Channel
    
    std::mutex mutex_;
    std::vector pendingFunctors_;  // 跨線程任務隊列
    bool callingPendingFunctors_; // 防止重入
};

核心循環:loop()

void EventLoop::loop() {
    assertInLoopThread();
    looping_ = true;
    
    while (!quit_) {
        activeChannels_.clear();
        // 1. I/O 多路復用等待事件
        poller_->poll(kPollTimeMs, &activeChannels_);
        
        // 2. 處理所有就緒 Channel
        for (Channel* channel : activeChannels_) {
            currentActiveChannel_ = channel;
            channel->handleEvent(receiveTime);  // 分發到各具體回調
        }
        currentActiveChannel_ = nullptr;
        
        // 3. 執行跨線程提交的任務
        doPendingFunctors();
    }
    looping_ = false;
}

跨線程任務提交:runInLoop / queueInLoop

void EventLoop::runInLoop(Functor cb) {
    if (isInLoopThread()) {
        cb();  // 同線程直接執行
    } else {
        queueInLoop(std::move(cb));  // 異線程入隊
    }
}

void EventLoop::queueInLoop(Functor cb) {
    {
        std::lock_guard lock(mutex_);
        pendingFunctors_.push_back(std::move(cb));
    }
    
    if (!isInLoopThread() || callingPendingFunctors_) {
        wakeup();  // 喚醒 EventLoop 處理新任務
    }
}

void EventLoop::wakeup() {
    uint64_t one = 1;
    ssize_t n = sockets::write(wakeupFd_, &one, sizeof(one));
    // eventfd 語意:寫入非零值觸發可讀事件
}

Channel:文件描述符事件封裝

class Channel : noncopyable {
public:
    using EventCallback = std::function;
    using ReadEventCallback = std::function;
    
    Channel(EventLoop* loop, int fd);
    ~Channel();
    
    // 事件註冊
    void setReadCallback(const ReadEventCallback& cb) { readCallback_ = cb; }
    void setWriteCallback(const EventCallback& cb) { writeCallback_ = cb; }
    void setCloseCallback(const EventCallback& cb) { closeCallback_ = cb; }
    void setErrorCallback(const EventCallback& cb) { errorCallback_ = cb; }
    
    // 向 Poller 註冊/修改/刪除事件
    void enableReading()  { events_ |= kReadEvent; update(); }
    void disableReading() { events_ &= ~kReadEvent; update(); }
    void enableWriting()  { events_ |= kWriteEvent; update(); }
    void disableWriting() { events_ &= ~kWriteEvent; update(); }
    void disableAll()     { events_ = kNoneEvent; update(); }
    void remove()         { disabled_ = true; remove(); }
    
    int fd() const { return fd_; }
    int events() const { return events_; }
    void setRevents(int revt) { revents_ = revt; }
    EventLoop* ownerLoop() const { return loop_; }
    
private:
    void update() { loop_->updateChannel(this); }
    void remove() { loop_->removeChannel(this); }
    
    // 事件分發入口
    void handleEvent(Timestamp receiveTime) {
        eventHandling_ = true;
        
        if ((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)) {
            if (closeCallback_) closeCallback_();
        }
        if (revents_ & (EPOLLERR | EPOLLNVAL)) {
            if (errorCallback_) errorCallback_();
        }
        if (revents_ & (EPOLLIN | EPOLLPRI | EPOLLRDHUP)) {
            if (readCallback_) readCallback_(receiveTime);
        }
        if (revents_ & EPOLLOUT) {
            if (writeCallback_) writeCallback_();
        }
        
        eventHandling_ = false;
    }
    
    EventLoop* loop_;
    const int fd_;
    int events_;      // 關注的事件
    int revents_;     // 實際發生的事件
    int index_;       // Poller 內部索引
    bool eventHandling_;
    bool disabled_;
    
    ReadEventCallback readCallback_;
    EventCallback writeCallback_;
    EventCallback closeCallback_;
    EventCallback errorCallback_;
};

Poller:I/O 多路復用抽象層

class Poller : noncopyable {
public:
    using ChannelList = std::vector;
    
    Poller(EventLoop* loop);
    virtual ~Poller();
    
    // 核心介面
    virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0;
    virtual void updateChannel(Channel* channel) = 0;
    virtual void removeChannel(Channel* channel) = 0;
    virtual bool hasChannel(Channel* channel) const = 0;
    
    static Poller* newDefaultPoller(EventLoop* loop);  // 工廠方法
    
protected:
    using ChannelMap = std::unordered_map;
    ChannelMap channels_;  // fd -> Channel*
    
    EventLoop* ownerLoop_;
};

// EPollPoller 實現 (Linux)
class EPollPoller : public Poller {
public:
    EPollPoller(EventLoop* loop);
    ~EPollPoller();
    
    Timestamp poll(int timeoutMs, ChannelList* activeChannels) override;
    void updateChannel(Channel* channel) override;
    void removeChannel(Channel* channel) override;
    bool hasChannel(Channel* channel) const override;
    
private:
    static const int kNew = -1;
    static const int kAdded = 1;
    static const int kDeleted = 2;
    
    void fillActiveChannels(int numEvents, ChannelList* activeChannels);
    void update(int operation, Channel* channel);  // EPOLL_CTL_ADD/MOD/DEL
    
    int epollfd_;
    std::vector events_;  // epoll_wait 輸出緩衝
};

epoll 核心操作

void EPollPoller::update(int operation, Channel* channel) {
    epoll_event event;
    event.events = channel->events();
    event.data.ptr = channel;
    int fd = channel->fd();
    
    if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) {
        // 錯誤處理...
    }
}

Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) {
    int numEvents = ::epoll_wait(epollfd_, events_.data(), static_cast(events_.size()), timeoutMs);
    Timestamp now(Timestamp::now());
    if (numEvents > 0) {
        fillActiveChannels(numEvents, activeChannels);
        if (static_cast(numEvents) == events_.size()) {
            events_.resize(events_.size() * 2);  // 動態擴容
        }
    }
    return now;
}

void EPollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) {
    for (int i = 0; i < numEvents; ++i) {
        Channel* channel = static_cast(events_[i].data.ptr);
        channel->setRevents(events_[i].events);
        activeChannels->push_back(channel);
    }
}

三大組件協作時序圖

註冊階段:
App → Channel::enableReading()
    → EventLoop::updateChannel()
        → Poller::updateChannel() → epoll_ctl(ADD)

事件循環:
EventLoop::loop()
    → Poller::poll() → epoll_wait()
        → fillActiveChannels() → activeChannels_
    → Channel::handleEvent() → readCallback_()
        → 用戶代碼 (如 Acceptor::handleRead)

跨線程喚醒:
OtherThread → EventLoop::queueInLoop(task)
    → pendingFunctors_.push_back()
    → EventLoop::wakeup() → write(eventfd)
        → EventLoop::loop() 下輪迴代
            → Poller::poll() 返回 (eventfd 可讀)
            → Channel::handleEvent() → handleRead()
                → read(eventfd) 消費數據
                → doPendingFunctors() → 執行 task

設計亮點總結

  1. 線程綁定斷言:`assertInLoopThread()` 到處佈防,編譯期/執行期雙重保障
  2. eventfd 跨線程通知:無鎖、高效、統一事件源 (同樣走 Poller)
  3. Channel 解耦:fd 與事件處理邏輯分離,Poller 不知業務細節
  4. 共享指標管理連線:`enable_shared_from_this` 保證回調中連線存活
  5. RAII 資源管理:Socket、Channel、Timer 自動清理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
類別職責關鍵成員
EventLoop事件循環、線程綁定、任務隊列Poller、TimerQueue、wakeupFd、pendingFunctors
Channel文件描述符事件封裝、回調綁定fd、events、revents、readCallback、writeCallback
PollerI/O 多路復用抽象 (epoll/poll/kqueue)pollFdList、ChannelMap、poll()