代码梳理
Thread创建与分配
event_channel回调函数
在muduo中,有三种类型的channel,包括
- 事件channel(event_channel) 这个就是普通的IO事件channel,当监听到Tcp连接有读、写、关闭、错误事件的时候,event_channel活跃
- accept_channel,仅在MainLoop中定义,监听新的连接到来的channel,(执行相应的回调函数,将新的连接分配给subLoop)
- 唤醒channel(wakeupChannel),用于唤醒当前eventLoop对应的线程,执行相应的功能
一致性哈希原理
一致性哈希分配实现原理图解
TcpConnection生命周期管理
TcpConnection类是muduo库最核心的类,唯一继承自enable_shared_from_this的类,唯一默认使用shared_ptr来管理的类。
这是因为其生命周期模糊,可能在连接断开的时候,还有其他地方持有它的引用,贸然delete会造成悬空指针。只有确保其他地方没有持有该对象引用的时候,才能安全地销毁对象。
一般来说,所有涉及TcpConnection的回调函数都应该设置shared_from_this。(理解为临时增加引用计数,保证在执行回调执行对象前不被销毁,调用完成后引用计数自动减1)
并且,TcpConnection使用tie专门绑定shared_from_this指针,可以确保channel在执行相应回调函数的时候,对应的TcpConnection不会被释放。
// 连接建立
void TcpConnection::connectEstablished()
{
setState(kConnected);
channel_->tie(shared_from_this());
channel_->enableReading(); // 向poller注册channel的EPOLLIN读事件
// 新连接建立 执行回调
connectionCallback_(shared_from_this());
}
智能指针
/*这里只能是弱智能指针,
如果tie_是shared_ptr,那么channel就会强持有Tcpconnection;
这样就会导致循环引用
TcpConnetion--->>>channnel--->>>TcpConnetion
最终造成对象无法释放,内存泄露
*/
std::weak_ptr<void> tie_;
bool tied_;
void Channel::tie(const std::shared_ptr<void> &obj)
{
tie_ = obj;
tied_ = true;
}
void Channel::handleEvent(Timestamp receiveTime)
{
if (tied_)//tied_为true,说明上层调用了需要绑定对象来“守护回调期间的生命周期”
{
// 防止对象析构导致回调悬空(如 TcpConnection)
std::shared_ptr<void> guard = tie_.lock(); // 临时提升为强智能指针。
if (guard)
{
handleEventWithGuard(receiveTime);
}
// 如果提升失败了 就不做任何处理 说明Channel的TcpConnection对象已经不存在了
// 如果提升成功,引用计数-1
}
else//有些时候可以不用tie 来保证安全
{
handleEventWithGuard(receiveTime);
}
}
唤醒机制
适用于eventLoop不在其对应的线程中执行的时候
void EventLoop::loop()
{
looping_ = true;
quit_ = false;
LOG_INFO("EventLoop %p start looping\n", this);
while (!quit_)
{
activeChannels_.clear();
pollRetureTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
//Poller将发生事件的channel添加到activeChannels_中
//可能是wakeupChannel_,eventChannel_,acceptorChannel_
for (Channel *channel : activeChannels_)
{
//调用对应channel的回调函数执行回调
//这是 poller->poll() 返回后,系统检测到某个 fd(比如 socket)可读、可写、出错,就会调用这个函数
//处理 IO 事件(来自内核 epoll)
channel->handleEvent(pollRetureTime_);
}
//处理其他线程投递过来的任务(非 IO 事件)
//来自runInLoop() ,跨线程调用
doPendingFunctors();
}
LOG_INFO("EventLoop %p stop looping.\n", this);
looping_ = false;
}