返回值的锁

    在多线程编程中,时刻需要注意加锁,这也是多线程编程中的一个难点。

    但是我们所用到的锁都是“协议锁”,即是一个“君子协定”,所谓“防君子不防小人”。这也是多线程编程中比较让人肾疼的地方。

    我觉得用“锁”这个名词对编程中的这种操作现象进行描述其实是不太合适的,反而会引起歧义,把它看成是门口挂的一块“告示牌”会更合适一些 ——— 一面写着“有人勿进”,一面写着“空闲可用”。

    你的线程作为一个“君子”,在到达访问临界资源的门(门上是没有锁的,也没办法给它装个锁)前,首先要看看这块告示牌,如果写着的是“有人勿进”,那么你就在门口等着,时不时再瞄一眼,看告示牌是不是翻了个面了,也可能是在你等得快睡着的时候被人叫醒。

    否则你就可以进去,顺便把优雅的将告示牌翻个面。

    等你从门里出来的时候,或许你可以看见门口也等了一大堆像你一样的君子了,那么就看你是默默翻转告示牌离开,还是和他们打声招呼了。

    如果所有的人都像你这么君子作风,那么应该没什么问题了,井然有序,虽然可能办事效率会很低啦。然而总保不准会有一两个非君子的小人,进门不看告示牌,不管三七二十一,冲进去拿了东西就走,还不顺手把门口的告示牌给翻一下。

    当然如果他进门的时候刚好是“空闲可用”状态,或者即便是有人,但他拿的东西也不是别人想要的,那么顶多也就是虚惊一场。怕就怕的是起了冲突,那么很不幸,你的软件可能就要崩溃了。。


下面说说我遇到的比较肾疼的问题:

    接手的项目实在是惨不忍睹。有太多诸如定义了一个单例类对象,必然是需要当多个线程访问的临界资源的,然而却提供着 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

#endif
    3.使用:
//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);

    然后基本上几个简单的正则替换就搞定了,崩溃是没有了,然而至于性能,呵呵,管他呢,毕竟我只是个擦屁股的,我还能奢望我自己做得有多好呢[笑哭脸]。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Python ,多线程并不能直接返回值。因为线程是并行执行的,所以它们之间无法直接共享变量或返回值。如果你需要获取线程执行的结果,可以使用以下方法之一: 1. 使用共享变量:你可以在主线程创建一个共享变量,在子线程对其进行修改,并在主线程等待子线程完成后获取该变量的值。这可以通过 `threading` 模块的 `Thread` 类和共享变量(如 `Queue`)实现。 下面是一个示例代码: ```python import threading def worker(result): # 在子线程修改共享变量 result.append("Hello from worker") # 创建共享变量 result = [] # 创建线程对象 thread = threading.Thread(target=worker, args=(result,)) # 启动线程 thread.start() # 等待线程结束 thread.join() # 输出共享变量的值 print(result) ``` 2. 使用回调函数:你可以定义一个回调函数,将其作为参数传递给子线程,并在子线程调用该回调函数来传递结果。这需要通过自定义的方式来实现。 下面是一个示例代码: ```python import threading def worker(callback): result = "Hello from worker" callback(result) def on_result(result): print(result) # 创建线程对象,传递回调函数 thread = threading.Thread(target=worker, args=(on_result,)) # 启动线程 thread.start() # 等待线程结束 thread.join() ``` 请注意,在多线程编程,对共享变量的访问需要进行适当的同步,以防止竞争条件和数据不一致的情况发生。可以使用(`Lock`)或其他同步机制来确保线程安全。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值