首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

当构造函数外泄this指针时

2013-10-22 
当构造函数泄露this指针时当一个类正在构造时在构造函数中将this泄露给了其它对象,这在单线程串行执行情况

当构造函数泄露this指针时

            当一个类正在构造时在构造函数中将this泄露给了其它对象,这在单线程串行执行情况下可能没有什么问题,但是在多线程下那么问题就比较大了。比如线程1负责构造这个对象A但是在构造函数中将this指针泄露给了其它线程所调用的对象B,不巧的是其它线程所调用的对象B看见A有些不爽将其析构了。那么最后A自以为一切构造好了返回,线程1然后对这个A操作,最后可怕的错误(比如段错误)无穷无尽的折磨线程1......

           模拟这个问题:假设有一个人A,餐馆B,A没钱就去餐馆B点菜吃饭,单线程模式下:A进入餐馆点菜->餐馆B炒菜(不辞辛劳)->A吃完了没钱付->餐馆B大为光火.....此后出现了一幕CATV不会报道的事件.......

           但是聪明的餐馆B现在学聪明了,也会利用高科技了,利用某种技术可以检测到用户是否有钱(比如和银行通奸哈哈)从而开启了个后台进程检测客户没钱立马轰走.....那么问题变成如下:

           线程1:客人A进入餐馆B点菜,点菜这个操作这里强加为:A将this指针泄露给了B

           线程2:餐馆B发现有客人来了->获取该客人的信息(这里是this指针)->通过科学技术发现客户没钱->不准厨房炒菜了,立马暴打客户一顿

           在这种模式下显然客户不可能吃完饭再挨揍了.....这就是泄露this指针的可怕之处,我还没有构造好,其它线程就把我给干掉了....我以后还咋活啊???

#include<iostream>#include<unistd.h>#include<pthread.h>#include<assert.h>using namespace std;class Hotel;//餐馆class Person{//人    public:        Person(int a,Hotel* h);//a是代表人身上多少钱,h是吃饭的餐馆        int  get(){            return *money;        }        ~Person();    private:        int* money;};class Hotel{//餐馆    public:        Hotel():flag(false),p(NULL){}        void check(){//餐馆检查客人是不是有钱            if(flag&&p->get()<=0){//flag用于是否有客人,p是客人若客人的钱get()小于等于0表示没钱要吃霸王餐啊,果断轰出去                p->~Person();//干掉这个吃霸王餐的人            }        }        void _register(Person* a){//注册是否有客人来,这个函数交给Person类即客人来了就告诉餐馆我来了            flag=true;            p=a;        }    private:        bool flag;        Person* p;};Hotel* h=new Hotel;Person::Person(int a,Hotel* h){    money=new int(a);    h->_register(this);//客人向餐馆注册    sleep(3);//休眠的原因是让构造函数在此停止,造成正在构造的情形(正在等菜....),那么餐馆的线程就有时间检查客人是不是有钱}Person::~Person(){    delete money;}void* worker1(void* arg){//客人线程    Person* temp=(Person*)arg;    temp=new Person(-10,h);//客人temp欠债10块(这里-10的money可以理解为一张催款单)还进了餐馆吃饭    cout<<temp->get()<<endl;//客人看下催款单还在不在...我还要去缴费呢...}void* worker2(void* arg){//餐馆工作线程    Person* p=(Person*)arg;//    sleep(1);//睡眠1s是为了让客人进入构造函数但是又没有离开构造函数    h->check();//在客人还没有构造完成时(比如正在等菜时...)立刻检查客人是否有钱,很不幸的是餐馆发现客人的催款单一怒把催款单销毁delete了,并欲把客人轰出去}int main(){    pthread_t pthd[2];    Person* one;//客人    int ret=pthread_create(&pthd[0],NULL,worker1,one);//客人线程    assert(ret==0);    ret=pthread_create(&pthd[1],NULL,worker2,h);//餐馆线程    assert(ret==0);    ret=pthread_join(pthd[0],NULL);    assert(ret==0);    ret=pthread_join(pthd[1],NULL);    assert(ret==0);    return 0;}
输出结果:

0        //本来客户预期是点完菜还要做其他事呢,可是餐馆发现他没钱立马暴打他并轰走他....想吃饱饭再挨打不可能了....

总结:

对象构造实现线程安全原则是:不要在构造期间泄露this指针即:不要在构造函数中注册回调函数,不要在构造函数中把this指针传给跨线程的对象,即使在构造函数最后一行也不行(比如基类A,子类B先构造基类A,A在构造最后一行向其它对象C注册了什么而B正在构造...,C拿着A的虚函数执行什么关于B的操作....发生了错误)。 不然让别的线程看到这个半成品对象会干出什么事谁也不知道(比如废掉对象)....那么那些注册回调函数的操作怎么办?不写在构造函数中,还可以写在其它成员函数中嘛,只不过使用起来多了次成员函数调用罢了。为了安全,你懂的....

热点排行