读书人

关于双重if的妙用有关问题。大家一起讨

发布时间: 2014-01-19 01:28:51 作者: rapoo

关于双重if的妙用问题。大家一起讨论讨论。。
今天在看书的时候看的这个问题。希望大家一起思考一下,代码如下:

volatile T* pInst = 0;
T* GetInstance()
{
if(pInst == NULL)
{
lock();
if(pInst == NULL)
pInst = new T;
unlock();
}
return pInst;
}

书上说,双重if在这里另有妙用,可以让lock的调用开销降低到最小。求解。。。考虑不出来啊。

可以先不用CPU乱序执行会打乱new那一句的执行,抛开逻辑,只看双重if。
[解决办法]
这个肯定涉及到多线程了,单线程根本就不需要 lock 这些。

在多线程的环境下,外面一个 if 使得绝大多数情况下都不会调用 lock/unlock 函数,当然就提高效率了。
lock()/unlock() 之间还需要使用一个 if 是保证了正确性,在执行 lock() 的过程中,可能其他线程修改了 pInst 变量。需要重新判断一次。
[解决办法]
首先说你这个是单例设计模式,并且考虑到使用多线程的安全性(加锁)。
单例模式的作用就是使该类对象在程序运行始末至多只有一个对象。
这里假设同时有两个线程A、B来访问GetInstance(),A和B同时执行第一个判断语句,结果一样,都进入了代码块,然后A、B又要lock(),但是lock()的设定就是只允许一个线程进入。假设A进入了,B在等待。
A进入后首先判断是不是NULL,也是成功进入代码块,也就是说new了一个对象。然后解锁返回对象。
唤醒B,这是B进入发现第二个判断通过不了(因为A已经new了一个对象)。这样的话B就直接解锁返回对象。

假设只有最外层的判断的话,那么B也会创建一个对象。这样的话就有两个对象在内存中了。
[解决办法]
double check lock

volatile T* pInst = 0;
T* GetInstance()
{
if(pInst == NULL)
{
lock();
if(pInst == NULL)
pInst = new T;
unlock();
}
return pInst;
}

相对于直接lock高效.
volatile T* pInst = 0;
T* GetInstance()
{
// if(pInst == NULL)
{
lock();
if(pInst == NULL)
pInst = new T;
unlock();
}
return pInst;
}

[解决办法]
在c++ 11中下面的实现是线程安全的.

T* GetInstance()
{
static T* pInst = new T;
return pInst;
}

[解决办法]
正解:

这个完全不需要有个“双重if”这么个专有名字,就是一种必要的写法而已。

关键的是里面的if,无论如何不能舍弃。否则可能创建多份实例。外边的if在实例已经创建的时候避免操作锁,提高了效率。

一步步分析如下:
if != NULL
{
lock
new
unlock
}
有bug,多线程的bug,可能多次new

lock
if != NULL
new
unlock
没有多次new的bug,但是有效率问题,每次都要lock一次

if != NULL
{
lock
if != NULL
new
unlock
}
所谓“双重if”,避免了上边的问题

ps:各种高屋建瓴者能否消失?

读书人网 >C++

热点推荐