大龙的博客

常用链接

统计

最新评论

欲加速,故生并发之策,存临界不可达,故而生锁,阻塞患于锁,固又生避阻之策 ---- 转

欲加速,故生并发之策,存临界不可达,故而生,阻塞患于,固又生避阻之策。。。 此刻主要想记录下关于并发中相关的内容,当然,我也只想记录一些真正有效用的东西。 可以说是衍生自并发,故谈并发必然至。 此篇不欲从减少临界区以提高并发度的角度来考虑,不会深度探索诸如如何基于CAS来构建高质量无数据结构等。 而是从反方向,从如何很好的运用策略的角度来考虑。 这里要强调的一点是,无论如何,临界区一个系统中基本上是必然存的。CAS的确可以很多地方通过自身机制来消去以达到化解临界区之目的。但是这个实现复杂度却又着实提升了,况且,也不是所有地方都能够或者值得去CAS。相比而言,比较容易理解。 好了,切入主题:并发之------策略! 好,首先是定界加策略。 定界加(Scoped Locking):能确保当控制进入到某一范围时,自动获得,而当控制离开范围时,自动释放,不管从该范围返回的路径是什么。 给段普通的C++代码sample: bool increment(const string &path) { Item *item = lookup_or_create(path); lock.acquire(); if(entry==0){ lock.release(); return false; } else { entry->increment_hit_count(); lock.release(); return true; } } 这段代码完全可以正常工作,但是lock.acquire()和lock.release()之间存着多路返回,如果以上情况复杂点,写代码的人不一定记得每个返回点都释放。OK, 就算情况不复杂,拿上面的例子来看,如果entry->increment_hit_count()抛出了个异常,那如何???很显然,得不到释放了,这显然会导致其它想要得到的线程永远阻塞。 那怎么样避免呢?定界加模式是正用于此。 你可以定义个哨兵类(guard)类,当控制进入一个区域时,哨兵类的构造函数自动获得一个,当控制离开这个区域时,哨兵类的析构函数自动释放该,因为根据C++的语义,即便程序中抛出一个异常,析构函数还是会执行。将哨兵类实例化,以定义临界区的方法和块区域中获得或释放。类似于autoPoint的手法,需要注意的是:一,哨兵类中要使用指向的指针而不是使用栈上对象,以防止对的复制或赋值;二,给哨兵类增加一个owner标志,用来表示哨兵是否成功获得了,该标志也可以指示当错误地使用静态/全局时,由“初始化错误”而导致的失败。通过析构函数中检查这个标志,可以避免当哨兵释放它并不拥有的而产生的运行时错误。 哨兵类代码示范: class Thread_Mutex_Gurad { public: Thread_Mutex_Guard(Thread_Mutex &lock):lock_(&lock), owner_ (false){ lock_->acquire(); owner_ = true; } ~Thread_Mutex_Guard(){ if(owner_) lock_->release(); } private: Thread_Mutex *lock_; bool owner_; Thread_Mutex_Guard(const Thread_Mutex_Guard &); void operator=(const Thread_Mutex_Guard &); }; 以上模式是基于C++的特性来玩的。C++栈对象离开作用域时,必然调用其析构,这是死规则,所以这样OK。 再拿java作下对比,如果使用synchronized关键字,OK,你不用理会上面的麻烦,JVM帮你搞定。但如果你用的是 ReentrantLock或者ReadWriteLock之类,那么,下面的写法基本上就是死规矩了。 lock.lock(); try{ } finally{ lock.unlock(); } 以上代码不能显示获取和释放,你可以很简单的给它加上。 现懒得写东西了,下文后续补上。。。。。。 java下也有个finalize方法来做实例的资源销毁,但是JVM作GC的时机不确定,并非对象离开作用域就立马调用。所以你不要拿java的对豍

posted on 2008-11-07 21:36 大龙 阅读(277) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理