返回值的锁
来源:互联网 发布:中国网络远程学校 编辑:程序博客网 时间:2024/05/29 15:13
在多线程编程中,时刻需要注意加锁,这也是多线程编程中的一个难点。
但是我们所用到的锁都是“协议锁”,即是一个“君子协定”,所谓“防君子不防小人”。这也是多线程编程中比较让人肾疼的地方。
我觉得用“锁”这个名词对编程中的这种操作现象进行描述其实是不太合适的,反而会引起歧义,把它看成是门口挂的一块“告示牌”会更合适一些 ——— 一面写着“有人勿进”,一面写着“空闲可用”。
你的线程作为一个“君子”,在到达访问临界资源的门(门上是没有锁的,也没办法给它装个锁)前,首先要看看这块告示牌,如果写着的是“有人勿进”,那么你就在门口等着,时不时再瞄一眼,看告示牌是不是翻了个面了,也可能是在你等得快睡着的时候被人叫醒。
否则你就可以进去,顺便把优雅的将告示牌翻个面。
等你从门里出来的时候,或许你可以看见门口也等了一大堆像你一样的君子了,那么就看你是默默翻转告示牌离开,还是和他们打声招呼了。
如果所有的人都像你这么君子作风,那么应该没什么问题了,井然有序,虽然可能办事效率会很低啦。然而总保不准会有一两个非君子的小人,进门不看告示牌,不管三七二十一,冲进去拿了东西就走,还不顺手把门口的告示牌给翻一下。
当然如果他进门的时候刚好是“空闲可用”状态,或者即便是有人,但他拿的东西也不是别人想要的,那么顶多也就是虚惊一场。怕就怕的是起了冲突,那么很不幸,你的软件可能就要崩溃了。。
下面说说我遇到的比较肾疼的问题:
接手的项目实在是惨不忍睹。有太多诸如定义了一个单例类对象,必然是需要当多个线程访问的临界资源的,然而却提供着 static MyCls& MyCls::GetMyCls();这种借口。然而本来应该提供的需要在内部加锁的“增删改查”接口可能却压根没有!!!
如果只是一个类这样写还好,自己重构一下问题不大,然而当整个项目几乎都这样的时候,我也无能为力。
面对偶发并且频率极高的崩溃,也只能死马当活马医,加锁吧。。。
需要在定义这个类的模块中增加锁成员,并且导出出去供其他模块使用,多么肾疼的写法。。。
好吧,只好用C语言强大万能的宏来包装一下,搞一个返回值的锁吧。
代码如下:
1. 封装锁:
//CriticalSection_Lock.h#pragma once#include <windows.h>class CriticalSection_Lock{public: CriticalSection_Lock(void); ~CriticalSection_Lock(void); //{重载new delete解决跨模块的析构 void *operator new(size_t size){return ::operator new(size);} void *operator new[](size_t size){return ::operator new(size);} void operator delete(void *p){return ::operator delete(p);} void operator delete[](void *p){return ::operator delete(p);} //}}private: static CRITICAL_SECTION *m_cs;};#define CS_LOCK(name) { CriticalSection_Lock lock_##name;#define CS_UNLOCK(name) }
//CriticalSection_Lock.cpp#include "CriticalSection_Lock.h"CRITICAL_SECTION *CriticalSection_Lock::m_cs = nullptr;CriticalSection_Lock::CriticalSection_Lock(void){ if (nullptr == m_cs) { static CRITICAL_SECTION cs;//实际的代码不应该这样写,也不是这么写的,这里只是给个简单的例子,用了一个全局的锁。不过即便像这样的示例代码,也是有问题的,需要使用双检锁避免创建多个cs实例(如果真的需要使用全局单例的话) m_cs = &cs; InitializeCriticalSectionEx(m_cs,4000,0); } EnterCriticalSection(m_cs);}CriticalSection_Lock::~CriticalSection_Lock(void){ LeaveCriticalSection(m_cs);}2.返回值锁相关的宏:
//RetValueLock.h#pragma once#define RETURN_NEED_LOCK#ifdef RETURN_NEED_LOCK#define RV_WITH_LOCK_DECL(Type) \struct RetWithLock##Type \{ \ RetWithLock##Type(Type type, std::shared_ptr<CriticalSection_Lock> sp) \ :m_type(type) \ ,m_sp(sp){} \ Type m_type; \ std::shared_ptr<CriticalSection_Lock> m_sp; \};#define RV_WITH_LOCK(Type) RetWithLock##Type#define RETURN_RET_WITH_LOCK(Type,name) \ CriticalSection_Lock *pcs = new CriticalSection_Lock; \ std::shared_ptr<CriticalSection_Lock> spint(pcs); \ return RetWithLock##Type(name,spint);#define GET_REAL_RET_FROM_LOCKRET(Name) Name.m_type#else#define RV_WITH_LOCK_DECL(Type)#define RV_WITH_LOCK(Type) Type#define RETURN_RET_WITH_LOCK(Type,name) return name;#define GET_REAL_RET_FROM_LOCKRET(Name) Name#endif3.使用:
//1.typedef成一个可以放进标识符的名字typedef MyCls& MyClsRef;//2.替换GetMyCls();等申明和实现//MyCls& MyCls::GetMyCls()RV_WITH_LOCK(MyClsRef) MyCls::GetMyCls(){ //....}//3.替换外部调用GetMyCls()的地方///MyCls& v = MyCls::GetMyCls();RV_WITH_LOCK(MyClsRef) lv = GetVct();MyClsRef v = GET_REAL_RET_FROM_LOCKRET(lv);
然后基本上几个简单的正则替换就搞定了,崩溃是没有了,然而至于性能,呵呵,管他呢,毕竟我只是个擦屁股的,我还能奢望我自己做得有多好呢[笑哭脸]。。。
- 返回值的锁
- 返回引用和返回值的差别
- 返回指针与返回值的区别
- 返回参数的值
- 返回值的理解
- SendMessage的返回值
- preparedstatement的返回值
- MessageBox的返回值
- InterlockedExchange的返回值
- mysql_insert_id的返回值
- sprintf 的返回值
- GetQueuedCompletionStatus的返回值
- scanf的返回值
- GetQueuedCompletionStatus的返回值
- mysql_query()的返回值
- 測試一個頁面輸入的返回值
- main()的返回值
- 返回AutoCompleteExtender的值
- CharacterController 角色移动
- MFC 热键
- static oc、ios 一个例子让你明白
- PCH was compiled with module cache oldpath newpath解决办法
- Hibernate入门
- 返回值的锁
- 面试专题之一Fragment的生命周期
- IOS 常用的宏
- 高并发下PHP请求Redis异常处理
- 取得spring上下文
- 信道估计算法
- Spinner的简单使用
- spark sql dataframe操作
- html5部分总结