轉自http://blog.csdn.net/SeaWave/archive/2006/05/21/747863.aspx
本文是觀大寶SODME的BLOG中文章有感,原文中提到了兩種方法(對數據緩沖區使用引用計數機制、在clientsock的對象設計機制上使釋放操作線性化),但只討論了第2種方法的實現。其實在多線程程序里,要讓一個釋放操作線性化,并不是一件容易的事情,這不僅僅是多個IOCP工作線程的問題(一般來說,我們會為每個CPU設立兩個IOCP工作線程),還涉及到其他業務邏輯線程的問題。
比方說,我們通常(就象文中也提到的)會將ClientSocket與接收緩沖區綁定到一個會話對象中(為簡化起見,發送數據往往沒有用overlapped機制,而是直接用一個異步send,也就不需要發送緩沖區),而這個對象可能被除IOCP工作線程以外的其他線程也用到,比方說一個事件隊列的處理線程(我們會在收到數據的時候生成事件對象置入隊例中,以類似于Command模式的方法來處理,而這些事件對象會引用到會話對象),或者,也許有某個容器會存放這些會話對象的一個引用,用于定時發送心跳包、會話計數、檢索等等,這個時候,會話對象的銷毀就不是那么簡單的了,換句話說,僅靠“將銷毀工作統一到執行GetQueuedCompletionStatus的函數里“是不夠的。
在這種情況下,文中提到的第1種“采用引用計數”的方法就比較優雅了,在我的很多實際應用中,都是將會話對象設計為“可引用計數”的,不暴露它的析構函數,而是當引用計數減到0的時候,自動銷毀,這樣就保證“僅當沒有任何人使用它的時候才會釋放它”。
利用C++的模板,可以十分方便地模擬出自動引用計數的安全指針:
001: /************************************************************************
002: 引用計數基類、及引用計數指針模板類
003: ----NoSound QQ2591570 可隨意復制、改動、使用、拍磚,概不追究!
004: ************************************************************************/
005: #ifndef _REFCOUNTED_INCLUDED_
006: #define _REFCOUNTED_INCLUDED_
007:
008: #include <cassert>
009: #ifdef _MT
010: #include <Windows.h>
011: #endif
012:
013: class RefCountable {
014: public:
015: int addRef(void) {
016: #ifdef _MT
017: return ::InterlockedIncrement(&refCount_);
018: #else
019: return ++refCount_;
020: #endif
021: }
022:
023: int decRef(void) {
024: int r =
025: #ifdef _MT
026: ::InterlockedDecrement(&refCount_);
027: #else
028: --refCount_;
029: #endif
030: assert(r>=0);
031: if (0==r)
032: delete this;
033: return r;
034: }
035:
036: int getRefCount(void) const { return refCount_; }
037:
038: protected:
039: RefCountable(void) : refCount_(0) {}
040: virtual ~RefCountable(void) { assert(0==refCount_); }
041:
042: private:
043: #ifdef _MT
044: long
045: #else
046: int
047: #endif
048: refCount_;
049: RefCountable(const RefCountable &);
050: RefCountable & operator = (const RefCountable &);
051: };
052:
053: template<class T>
054: class RefCountedPtr {
055: public:
056: RefCountedPtr(void) : ptr_(0) {}
057: RefCountedPtr(T *ptr) : ptr_(ptr) {
058: if (ptr_)
059: ptr_->addRef();
060: }
061: RefCountedPtr(const RefCountedPtr<T> &sour) : ptr_(sour.ptr_) {
062: if (ptr_)
063: ptr_->addRef();
064: }
065: RefCountedPtr & operator = (const RefCountedPtr<T> &right) {
066: if (this!=&right) {
067: if (0!=ptr_)
068: ptr_->decRef();
069: ptr_ = right.ptr_;
070: if (ptr_)
071: ptr_->addRef();
072: }
073: return *this;
074: }
075: ~RefCountedPtr(void) {
076: if (0!=ptr_)
077: ptr_->decRef();
078: }
079:
080: T & operator*() const { return *ptr_; }
081: T * operator->() const { return (&**this); }
082:
083: friend bool operator == (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
084: return (left.ptr_ == right.ptr_);
085: }
086: friend bool operator != (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
087: return (left.ptr_ != right.ptr_);
088: }
089: friend bool operator < (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
090: return (left.ptr_ < right.ptr_);
091: }
092: friend bool operator > (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
093: return (left.ptr_ > right.ptr_);
094: }
095: friend bool operator <= (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
096: return (left.ptr_ <= right.ptr_);
097: }
098: friend bool operator >= (const RefCountedPtr<T> &left, const RefCountedPtr<T> &right) {
099: return (left.ptr_ >= right.ptr_);
100: }
101:
102: bool isNull() const { return 0==ptr_; }
103: bool isValid() const { return 0!=ptr_; }
104:
105: // 返回所控制的對象指針
106: T * get(void) const { return ptr_; }
107:
108: //取得對另一指針的控制權
109: void reset(T * ptr=0) {
110: if (0!=ptr)
111: ptr->addRef();
112: if (0!=ptr_)
113: ptr_->decRef();
114: ptr_ = ptr;
115: }
116:
117: private:
118: T *ptr_;
119: };
120:
121: #endif // ifndef _REFCOUNTED_INCLUDED_