为什么释放一个TcpConnection会如此复杂?
首先要知道客户端关闭连接,在服务端TcpConnection对象所属的Channel对象返回的是可读事件。
因此从TcpServer的map<string, shared_ptr<TcpConnection>>中移除这个TcpConnection对象都是在TcpConnectoin所属的Channel对象的Channel::handleEvent()函数内进行的。
如果在这个TcpConnection对象的函数执行过程中释放了这个对象,那么就会造成不可预计的后果。(大概率就是coredump)
因此待释放的TcpConnection对象的生命期一定要长于Channel::handleEvent()函数。
如何做到正确释放一个TcpConnection对象的?
最重要的是在每一个TcpConnection建立的时候将他的shared_ptr赋值给了他所属的Channel对象的weak_ptr。
void TcpConnection::connectEstablished() { loop_->assertInLoopThread(); assert(state_ == kConnecting); setState(kConnected); channel_->tie(shared_from_this()); channel_->enableReading(); connectionCallback_(shared_from_this()); }
这样当有TcpConnection所属的Channel有事件到来的时候就可以对TcpConnection的引用计数+1:此时TcpServer的map中有一个智能指针指向TcpConnection
void Channel::handleEvent(Timestamp receiveTime) { std::shared_ptr<void> guard; if (tied_) { guard = tie_.lock(); if (guard) { handleEventWithGuard(receiveTime); } } else { handleEventWithGuard(receiveTime); } }
整一个流程为:
简略的函数压栈情况: