【Channel】

Channel 类是网络编程中事件驱动模型的核心组件之一,主要用于封装文件描述符(如套接字、定时器等)及其对应的事件和回调函数。

  1. Channel与Socket对象的fd是聚合关系,一个fd对应一个channel,不实际拥有fd,Channel析构不会close当前的fd。
  2. Channel一般作为其他类的成员,不会被直接使用,而使用更上层的封装,例如服务端的Acceptor,用于客户端的Connector,用于一次客户端服务通信的TcpConnection。最重要的是,EventLoop通过vector<Channel*>数组对注册到到其内的众多fd的管理。
  3. 它与 EventLoop 和 Poller 紧密协作,实现了事件的注册、监听和处理。具体作用如下:

1. 事件管理:Channel 类负责管理文件描述符感兴趣的事件(如可读、可写、错误等),并提供了一系列方法来注册和注销这些事件。

2.  事件回调:通过设置不同的回调函数(如读回调、写回调、关闭回调、错误回调),Channel 类可以在相应事件发生时执行特定的操作。

3. 多线程安全:通过 tie 方法,Channel 类可以捆绑一个共享指针,用于在多线程环境中监听对象的生存情况,确保在对象销毁时不会发生错误。
我们知道,当客户端正常断开TCP连接,IO事件会触发Channel中的设置的`CloseCallback`回调,但是用户代码在`onClose()`中有可能析构Channel对象,导致回调执行到一半的时候,其所属的Channel对象本身被销毁了。这时程序会出现问题。muduo的解决办法是提供`Channel::tie(const boost::shared_ptr<void>&)`这个函数,用于延长某些对象的生命期,使之长过`Channel::handleEvent()`函数。所以muduo库中的 `TcpConnection`采用了shared_ptr管理对象生命期。
 

成员变量

private:
	EventLoop *loop_;    // 当前Channel 关联的 EventLoop
    const int fd_;       // Poller监听的文件描述符
    int events_;         // 注册fd感兴趣的事件.写入epoll的事件
    int revents_;        // poller返回的具体发生的事件,从epoll读取的事件
    int index_;          // 在Poller上注册的情况: KNew kAdded kDeleted

	//用于多线程
    std::weak_ptr<void> tie_; // 多线程中监听对象的生存情况
    bool tied_;               // 捆绑
    bool eventHandling_; // 是否处于事件循环中(正处理事件)
    bool addedToLoop_;   // 是否已被添加到事件循环
        
    // 处理事件的回调函数
    ReadEventCallback readCallback_;  //lfd   cfd
    EventCallback writeCallback_;     //cfd
    EventCallback closeCallback_;     //cfd
    EventCallback errorCallback_;     //cf
    
 public:
	 // 事件回调函数定义
    using EventCallback = std::function<void()>;
    // 读事件回调函数定义
	using ReadEventCallback = std::function<void(Timestamp)>;

常量定义

    static const int kNew = -1;    // Channel 要添加到map和epoll红黑树中
    static const int kAdded = 1;   // Channel 在map 和 epoll 的红黑树中
    static const int kDeleted = 2; // Channel 在map中,但是不在epoll 的红黑树中

重要方法

void handleEvent(Timestamp receiveTime)
{
    std::shared_ptr<void> guard;  // 创建空的强引用

    if (tied_)  // 若已绑定TcpConnection对象
    {
        guard = tie_.lock();  // 尝试将弱引用提升为强引用
        if (guard)  // 若提升成功,说明对象仍存活
        {
            handleEventWithGuard(receiveTime);  // 安全处理事件
        }
        // 若提升失败(guard为空),则不处理事件,直接返回
    }
    else  // 若未绑定TcpConnection对象(如独立Channel)
    {
        handleEventWithGuard(receiveTime);  // 直接处理事件
    }
}

在这里,我们可以看出`handleEvent`中tie实际上这是一个弱指针,绑定到`TcpConnection`的共享指针 ,如果可以原来的弱指针,变成了强指针,这时候tie()的作用就表明了,延长了`TcpConnection`的生命周期,使之长过`Channel::handleEvent()`,保证了`TcpConnection`不被销毁,因此Channel中存了一个`TcpConnection`的弱指针,在处理事件的时候,lock将引用计数加1,`Channel::handleEvent()`来关闭连接时,guard变量依然持有一份`TcpConnection`。也就是说Channel不会在执行完`Channel::handleEvent()`之前被析构。 

    //捆绑一个共享指针,用于多线程中监听对象的生存情况
    //obj 要捆绑的共享指针
     
    void tie(const std::shared_ptr<void> &obj)
    {
        tie_ = obj;
        tied_ = true;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值