C++中的单例模式并非想像得这么简单

C++写单例模式v1版

class Singlon
{ 
private:
    static Singlon * inst;

public:      
    static Singlon& instance()
    {
        if(inst != NULL) 
        {
            return *inst;
        }
        else 
        {
            inst = new Singlon();             
            return *inst;
        }
    } // instance
}; // class Singlon

Singlon* Singlon::inst = NULL;

v1是一份很标准的单例模式代码,但不够实用。

回想C++中的线程互斥,考虑LINUX C下互斥锁,于是乎就有了改进的v2版

class Singlon
{ 
private:
    static Singlon * inst;
    pthread_mutex_t inst_lock;

public:
    static Singlon& instance()
    {
        if(inst != NULL)
        {
            return *inst;
        }
        else 
        {
            pthread_mutex_lock(&inst_lock);
            if(inst == NULL)
            {
                inst = new Singlon();
            } // if
            pthread_mutex_unlock(&inst_lock);
            return *inst;
        } // else
    } // instance
}; // class Singlon

Singlon* Singlon::inst = NULL;
Singlon::inst_lock = PTHREAD_MUTEX_INITIALIZER;

v2中首先直接判断inst是否为NULL,若不为NULL则避免调用互斥锁,因为互斥锁不仅使用系统调用,而且将导致多线程竞争等待,产生睡眠。

发现if语句确实还可以有优化的余地,v3版:

class Singlon
{ 
private:
    static Singlon * inst;
    pthread_mutex_t inst_lock;

public:
    static Singlon& instance()
    {
        if(likely(inst != NULL)) 
        {
            return *inst;
        }
        else 
        {
            pthread_mutex_lock(&inst_lock);
            if(likely(inst != NULL))
            {
                pthread_mutex_unlock(&inst_lock);
                return *inst;
            } // if
            else 
            {
                inst = new Singlon();
                pthread_mutex_unlock(&inst_lock);
                return *inst;
            } // else
        } // else
    } // instance
}; // class Singlon

Singlon* Singlon::inst = NULL;
Singlon::inst_lock = PTHREAD_MUTEX_INITIALIZER;

v3由于互拆锁会导致效用问题,越尽早释放越好,所以将一条if语句拆成两条、迟早释放,并且将条件概率大的情况放到if而非else中,用likely在汇编层上优化。换了个思路,写下v4版:

class Singlon
{ 
private:
    static Singlon * inst;

public:
    static Singlon& instance()
    {           
        return *inst;
    } // instance
}; // class Singlon

Singlon* Singlon::inst = new Singlon();

v4预先创建好一个对象。虽然浪费空间,但不用再考虑线程互斥问题。

MutexLock使用SpinLock实现互斥,循环检测并休眠。当时突然想起可以直接用SpinLock实现v3的互斥,因为竞争仅发生一次,SpinLock直接采用循环检测不休眠的方式,使用“内存屏障”、“CPU屏障”等技术保证内存和CPU指令的“有序”。v5版如下: 

class Singlon
{ 
private:
    static Singlon * inst;
    static raw_spinlock_t inst_lock;

public:
    static Singlon& instance()
    {
        if(likely(inst != NULL)) 
        {
            return *inst;
        }
        else 
        {
            spin_lock(&inst_lock);
            if(likely(inst != NULL))
            {
                spin_unlock(&inst_lock);
                return *inst;
            } // if
            else 
            {
                inst = new Singlon();
                spin_unlock(&inst_lock);
                return *inst;
            } // else
        } // else
    } // instance
}; // class Singlon

Singlon* Singlon::inst = NULL;
spin_lock_init(Singlon::inst_lock);

其实,v5版本还可以优化,例如采用无锁的办法。但总得说来,只是将spin_lock的代码简化了一下内嵌进来。不知道是否有哪位高人可以指点一二,给一个最终优化的C++版单例模式?


《无锁队列的实现》,http://www.kuqin.com/algorithm/20120907/330193.html

 

 转自:http://www.cnblogs.com/icanth/archive/2012/12/10/2811855.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值