讀者來信用黑色,個人回答用藍色。通過整理,接近對話體。api
> 陳碩,你好,
>
> 閱讀了你的書,頗有收穫。
> 可是沒有在moduo的源代碼裏面找到實現線程模型11的例子。即one thread per loop + thread pool。
> 謝謝。函數
書第 173 頁圖 6-14 下面的第一段話,具體改動方法參考前一頁的 diff。oop
> 謝謝。
>
> 另外TcpConnection和Channel的生命週期管理有點問題。
> TcpConnection若是已經被回收了,其包含的Channel也已經被回收了。而這個時候在Channel::handleEvent()裏面檢查tied_和tie_是危險的。由於其內存已經被回收了。
>
> 若是用戶保證TcpConnection被回收以後,不會再用Channel的裸指針,則沒有必要在TcpConnection::connectEstablished()中call tie().優化
TcpConnection 回收以前,會調用 connectDestroyed,其中調用 channel_->remove();,這樣就不可能再會有 Channel::handleEvent() 被調用了。ui
tie() 的做用是防止 Channel::handleEvent() 運行期間其 owner 對象析構,致使 Channel 自己被銷燬。線程
> > TcpConnection 回收以前,會調用 connectDestroyed,其中調用 channel_->remove();,這樣就不可能再會有 Channel::handleEvent() 被調用了。
> 這個時候會不會有race condition?假設如今有兩個active channels,處理頭一個的時候回收TcpConnection,而第二個channel恰好對應這個connection。debug
這時你沒有辦法強制銷燬 TcpConnection,只能下降其引用計數,因此不會有問題。你能夠寫段代碼試試。指針
> 另外底層的poller OS api是否保證unregister channel以後必定不會再有這個channel的事件,會清空內核的已經就緒的事件隊列?對象
跟內核不要緊,Poller class 在 unregister channel 以後就不可能調用其 handleEvent() 成員函數。生命週期
> 那EPollPoller::fillActiveChannels()的改一改,「assert(it != channels_.end());」再也不適用了,並且每次都個event都要查一次map。效率會有問題。
assert() 只有在 debug build 才執行,不會影響效率。
再說每一個 event 都要涉及 read/write 等系統調用,開銷比「查一次 map」大得多,優化這裏是無用功。
> 但這個assert()不是invalid了嗎?你可能以前在unregister channel的時候已經從map裏面remove掉了它。
這個 assert 是有效的,你再想一想。
> > tie() 的做用是防止 Channel::handleEvent() 運行期間其 owner 對象析構,致使 Channel 自己被銷燬。
> 這個也不太make sense。仍然有race conditon。在Channel::handleEvent()擁有guard鎖定ownner以前,Channel::handleEvent()須要檢查其tied_。
你再想一想,tie 的做用是防止調用 handleEvent() 期間對象銷燬(好比調用 closeCallback 期間),不是也不可能防止調用 handleEvent() 以前對象銷燬。
> 恩,是的。整個TcpConnection, Channel, EventLoop都是一個thread裏面run的。