狗尾续貂:利用引用计数在多线程中安全释放资源
来源:互联网 发布:百电通 软件下载 编辑:程序博客网 时间:2024/05/17 22:53
原文地址:http://blog.csdn.net/SeaWave/article/details/747863
原文标题:IOCP中的socket错误和资源释放处理方法
原文作者:sodme
原文地址:http://blog.csdn.net/sodme/archive/2006/04/17/666062.aspx
原作者声明:本文可以不经作者同意任意转载、复制、传播,但任何对本文的引用均须保留本文的作者、出处及本行声明信息!谢谢!
原文作者:sodme
原文地址:http://blog.csdn.net/sodme/archive/2006/04/17/666062.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_
- 狗尾续貂:利用引用计数在多线程中安全释放资源
- 狗尾续貂:利用引用计数在多线程中安全释放资源
- 在Java中做到真正安全的释放数据库资源
- 关于std::string的引用计数在多线程中产生的问题
- 在多线程中释放List所占用的资源-List.removeall(List);
- java多线程计数及释放
- 在Win 2003中安全释放内存
- 多线程中的资源释放
- WebBrowser 在多线程中,无法释放内存
- 在谈引用计数
- 今天谈谈OC中MRC手动引用计数的内存释放问题
- socket多线程安全性 引用计数
- linux多线程-线程资源释放
- 有关可能在遍历中进行资源释放的资源释放过程设计
- Effective C++之利用std::tr1::shared_ptr指定“删除器”实现对底层资源“引用计数”
- pyhton中引用计数
- dashboard中资源释放
- 在Win2003中安全的释放内存方法
- Android随笔--短小精悍的代码段(持续更新)
- Android画图学习总结
- javascript学习(一)——基本语法
- 2012曲靖市事业单位考试
- Fedora15 sjtu源
- 狗尾续貂:利用引用计数在多线程中安全释放资源
- iPhone Network 编程
- mina2实例
- C#博文收集
- Adapter 模式 - Class Adapter
- Asterisk Registry(registe an account to local asterisk server)
- C/C++ New与Delete
- 关于maven的不错的文章
- 编写大容量和健壮的服务器系列—处理IOCP资源释放