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

原文标题: 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_
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
BES-CMS Common Style Mistakes, Part 1 Common Style Mistakes, Part 2 Developing Secure Web Applications Discuz 得到cookies的漏洞 Discuz! 漏洞 Discuz漏洞大全 Discuz论坛短消息未限制发送次数漏洞 Fingerprinting Port80 header-based-exploitation HotNews arbitary file inclusion Invision Power Board IP地址伪造漏洞 Invision Power Board SQL Injection Vulnerabil Invision Power Board v1.3 Final ssi.php SQL Injection Vulnerability IPB SQL Injection L'injection (My)SQL via PHP L'injection (My)SQL via PHP Mambo Site Server非法获得administrator权限 Multiple vulnerabilities in Psychoblog NetObserve Security Bypass Vulnerability newsPHP 存在任意文件的上传和不全面的登入确认漏洞 Ofstar和phpind论坛安全性分析 Ofstar论坛安全性分析 osCommerce SQL Injection && DoS && Cross Site PHP Networking PHP Security, Part 3 PHP Session Management With Cookies PHP 安全(1) PHP 安全(2) PHP 4.1.0 的 php.ini 的全文翻译 php.ini文版 phpBB viewtopic.php SQL 注入缺陷 phpBB存在多个安全缺陷 PHP安全配置 Php部分常见问题总结 PHP程序如何防止站外提交数据 php的正则表达式专题 php通用检测函数集 PHP的POST&GET的应用 PHP注入实例 Portable PHP Code ProjectForum Multiple Vulnerabilities PTNews远程管理脚本未授权访问缺陷 Session Tracking Part I Session Tracking Part 2 Ten Security Checks for PHP, Part 1 Ten Security Checks for PHP, Part 2 The Cross Site Scripting FAQ VBulletin 跨站脚本缺陷使用代码 WDB论坛漏洞 Webfroot Shoutbox远程命令执行漏洞 Webmin-Usermin Session ID欺骗未授权可访问漏洞 welcome xss-faq Zend Optimizer加速php ZendCache使你的站点飞起来 对PHP程序的常见漏洞进行攻击之狗尾续貂 对PHP程序的常见漏洞进行攻击之狗尾续貂 非常有用的环境变量$_SERVER,$_ENV等等 关于PHP操作MySQL数据库的一些要注意的问题 灰色论坛漏洞 几个php病毒的源代码 将PHP作为Shell脚本语言使 经验积累,献给PHP爱好者!!! 漂亮但不安全的CTB论坛--CTB论坛再探 如何对PHP程序的常见漏洞进行攻击(上) 如何对PHP程序的常见漏洞进行攻击(下) 入侵服务器 搜索引擎技术核心揭密(PHP) 谈php+mysql注射语句构造 通过对php一些服务器端特性的配置加强php的安全 学习phpnuke漏洞 用PHP函数解决SQL injection 在php使用sockets从新闻组获取文章 紫桐VBB2.28论坛漏洞利用攻击实例

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值