缩略muduo库:事件循环 EventLoop

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缩略muduo库:事件循环 EventLoop相关的知识,希望对你有一定的参考价值。

获取线程ID

每一个线程都有一个EventLoop,每个loop里面都会有很多的channel,每个channel的任务都要在自己的线程中完成。
为了管理这些线程,设置了一份获取线程ID的代码,辅助管理。

#pragma once

#include<unistd.h>
#include<sys/syscall.h>

namespace CurrentThread{
    //__thread:这个变量虽然是一个全局变量,但是加上这个修饰的话,其在每一个线程中都会保有一份缓存,互不干扰
    extern __thread int t_CachedTid;   
    extern __thread char t_TidString[32]; 
    extern __thread int t_TidStringLength; 
    extern __thread const char* t_ThreadNum;

    void cacheTid();    //做一份缓存

    inline int tid(){
        if (__builtin_expect(t_CachedTid == 0, 0)){ //底层优化,不再赘述
        cacheTid();
        }
        return t_CachedTid;
    }


    // for logging
    inline const char* tidString() {
        return t_TidString;
    }

    // for logging
    inline int tidStringLength() {
        return t_TidStringLength;
    }

    inline const char* name(){
        return t_ThreadNum;
    }
}
 

#include "currenthread.hpp"

#include<stdio.h>

namespace CurrentThread{
    __thread int t_cachedTid = 0;
    __thread char t_tidString[32];
    __thread int t_tidStringLength = 6;
    __thread const char* t_threadName = "unknown";

    void cacheTid(){
        if (t_CachedTid == 0){
            t_CachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
            t_TidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
        }
    }
}

事件循环 EventLoop

太恐怖了,cc文件莫名丢失,赶紧来备份一下。。。

#pragma once

#include "nocopyable.hpp"
#include "timestamp.hpp"
#include "currenthread.hpp"

#include <atomic>
#include <functional>
#include <memory>
#include <sys/eventfd.h> //去了解一下
#include <fcntl.h>
#include <mutex>
#include <vector>

class Channel;
class Poller;

class EventLoop:public nocpoyable{
public:
    //typedef std::function<void()> Functor;
    using Functor = std::function<void()>;

    EventLoop();
    ~EventLoop();  
 
    void loop();
    void quit();

    timestamp pollReturnTime() const { return pollReturnTime_; }

    void runInLoop(Functor cb); //在当前loop中运行
    void queueInLoop(Functor cb);//放到队列中,唤醒loop所在的线程去执行

    void wakeup();  //唤醒loop所在的线程

    //Poller的方法
    void updateChannel(Channel* channel);
    void removeChannel(Channel* channel);
    bool hasChannel(Channel* channel);

    bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
    
private:

    void handleRead();  // waked up
    void doPendingFunctors();   //执行回调

    using ChannelList = std::vector<Channel*>;
    std::atomic_bool looping_;  //原子操作的bool值
    std::atomic_bool quit_; //退出loop循环
    std::atomic_bool callingPendingFunctors_; //是否有需要回调的操作
    const pid_t threadId_;
    timestamp pollReturnTime_;  //返回发生事件的时间点

    std::unique_ptr<Poller> poller_;
  
    int wakeupFd_; 
    //当mainloop获取一个新用户的channel时,通过轮询算法选择一个subloop,
    //通过该成员唤醒subloop

    std::unique_ptr<Channel> wakeupChannel_;

    ChannelList activeChannels_;
    Channel* currentActiveChannel_;

    std::mutex mutex_;
    std::vector<Functor> pendingFunctors_;   //存储loop需要的所有回调操作
};
#include "eventloop.hpp"
#include "logger.hpp"
#include "poller.hpp"
#include "channel.hpp"

#include <mutex>

//防止一个线程创建多个EventLoop
__thread EventLoop *t_loopInThisThread = nullptr;

//定义默认的poller超时时间
const int kPollTimers = 10000;

//通过轮询的方式唤醒channel
int createEventfd(){
    int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (evtfd < 0){
        LOG_ERROR("Failed in eventfd%d\\n", errno);
    }
    return evtfd;
}

EventLoop::EventLoop()
    : looping_(false),
      quit_(false),
      callingPendingFunctors_(false),
      threadId_(CurrentThread::tid()),
      poller_(Poller::newDefaultPoller(this)),
      wakeupFd_(createEventfd()),
      wakeupChannel_(new Channel(this, wakeupFd_)),
      currentActiveChannel_(nullptr)
{
    LOG_DEBUG("EventLoop created %p in thread\\n", threadId_);
    if (t_loopInThisThread){
        LOG_FATAL("Another EventLoop %p exists in this thread %d\\n", t_loopInThisThread, threadId_);
    }
    else{
        t_loopInThisThread = this;
    }

    //设置wakeup事件类型及发生事件后的回调操作
    wakeupChannel_->setReadCallback(std::bind(&EventLoop::handleRead, this));

    //每一个EventLoop都将监听wakeupchannel的EPOLL读事件
    wakeupChannel_->enableReading();
}

EventLoop::~EventLoop(){
    wakeupChannel_->disableAll();
    wakeupChannel_->remove();
    ::close(wakeupFd_);
    t_loopInThisThread = nullptr;
}

void EventLoop::loop(){
    looping_ = true;
    quit_ = false; // FIXME: what if someone calls quit() before loop() ?
    LOG_INFO("EventLoop %p start looping \\n",this);

    while (!quit_){
        activeChannels_.clear();
        pollReturnTime_ = poller_->poll(kPollTimers, &activeChannels_);

        for (Channel *channel : activeChannels_){
            currentActiveChannel_ = channel;
            currentActiveChannel_->handleEvent(pollReturnTime_);
        }
        currentActiveChannel_ = NULL;

        //执行当前EventLoop事件循环需要的事件操作
        doPendingFunctors();
    }

    LOG_INFO("EventLoop %p stop looping\\n",this);
    looping_ = false;
}

void EventLoop::quit(){
    quit_ = true;
   
    if (!isInLoopThread()){
        wakeup();
    }
}

void EventLoop::runInLoop(Functor cb){
    if (isInLoopThread()){
        cb();
    }
    else{
        queueInLoop(std::move(cb));
    }
}

void EventLoop::queueInLoop(Functor cb){
    
    {
        std::unique_lock<std::mutex> lock(mutex_);
        pendingFunctors_.push_back(std::move(cb));
    }

    if (!isInLoopThread() || callingPendingFunctors_){
        wakeup();
    }
}

void EventLoop::updateChannel(Channel *channel){
    poller_->updateChannel(channel);
}

void EventLoop::removeChannel(Channel *channel){
    poller_->removeChannel(channel);
}

bool EventLoop::hasChannel(Channel *channel){
    return poller_->hasChannel(channel);
}

void EventLoop::wakeup(){
    uint64_t one = 1;
    ssize_t n = write(wakeupFd_, &one, sizeof one);
    if (n != sizeof one){
        LOG_ERROR("EventLoop::wakeup() writes %d bytes instead of 8 \\n",n);
    }
}

void EventLoop::handleRead(){
    uint64_t one = 1;
    ssize_t n = read(wakeupFd_, &one, sizeof one);
    if (n != sizeof one){
        LOG_ERROR("EventLoop::handleRead() reads %d bytes instead of 8\\n", n);
    }
}

void EventLoop::doPendingFunctors()
{
    std::vector<Functor> functors;
    callingPendingFunctors_ = true;

    {
        std::unique_lock<std::mutex> lock(mutex_);
        functors.swap(pendingFunctors_);
    }

    for (const Functor &functor : functors)
    {
        functor();
    }
    callingPendingFunctors_ = false;
}

以上是关于缩略muduo库:事件循环 EventLoop的主要内容,如果未能解决你的问题,请参考以下文章

缩略版muduo网络库:事件处理器 Chanel

缩略版muduo网络库:事件处理器 Chanel

Muduo网络库源码分析 EventLoop事件循环(Poller和Channel)

缩略muduo网络库事件分发器poller

缩略muduo网络库事件分发器poller

缩略muduo库:TcpServer