狗尾续貂:利用引用计数在多线程中安全释放资源

原创 2006年05月21日 15:52:00
原文标题:IOCP中的socket错误和资源释放处理方法
原文作者: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_
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

《Objective-C高级编程 iOS与OS X多线程和内存管理》学习笔记——第一章自动引用计数

第一章:自动引用计数 一、什么是自动引用计数 二、内存管理/引用计数 1、概要 2、内存管理的思考方式 3、alloc/retain/release/dealloc实现 4、苹果的实现 5、aut...

ATL学习笔记(1):ATL单线程与多线程套间对象引用计数的基础实现

COM对象必须在套间中运行。套间分为单线程套间和多线程套间。在单线程套间中,套间保证COM对象实例仅有一个线程可以访问,而在多线程套间中,COM对象实例可同时被多个线程访问。因此,在多线程套间中执行的...

文章标题 boost指针的引用计数,以及引发的资源共享和boost指针的交叉问题

我们平常使用的指针也叫裸指针,大家都知道申请内存时我们需要手动,但是有时候会因为使用完而忘记释放资源而引起内存上的泄漏。那么如何能保证我们手动申请的资源不会发生这种情况? 这时候boost指...

MeadiaPlayer的异步释放资源+线程处理

在用MediaPlayer类来写播放器的过程中,我们能够发现,新建的MediaPlayer对象在调用start方法后,关闭了所在的activity,Meadia播放并没有停止,那是引起mediapla...

ThreadLocal:多线程共享资源安全访问新思路

ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,由于Key值不可重复,...

iOS 开发 多线程详解之线程安全(资源共享)

多线程操作共享资源的问题 共享资源 资源 : 一个全局的对象、一个全局的变量、一个文件. 共享 : 可以被多个对象访问. 共享资源 :可以被多个对象访问的资源.比如全局的对象,变量,文件. 在多线程...

单片机引用计数

  • 2012-08-20 19:32
  • 482KB
  • 下载

使用pthread 线程退出时自动释放资源

线程退出时自动释放资源 今天碰到一个问题:主线程pthread_create一个子线程A,子线程pthread_mutex_lock,然后调用其他...

【amazing cocos2d-x 3.0之十三】内存管理(1):引用计数(Reference Count)和自动释放池(AutoReleasePool)

1. 引用计数 引用计数shi

iOS内存管理之:引用计数、ARC、自动释放池autoreleasepool和便捷方法之间的关系

部分内容摘自《Objective-C基础教程》和互联网 引用计数        Cocoa采用了引用计数(reference counting)机制,每一个对象有一个关联的“整数retainCount...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)