linux 线程 传指针,使用二级指针在多线程进行刷新操作

多线程程序中,我们经常会遇到这种情况,主线程启动时加载一些参数到内存中的某个对象或者数据结构中,将这个对象或数据结构作为参数传入各个子线程中,为了避免对象的复制与拷贝,往往传入的是指针,子线程启动,进行业务逻辑处理,需要根据key值获取hashtable中的value,value = m_pParam->get(key),代码如下所示

//用hashtable保存程序运行所需的参数

hashtable hashParam;

void loadParam(hashtable & hashParam)

{

//加载参数

return;

}

//模拟线程类

class ThreadX

{

public:

ThreadX(hashtable *pParam):m_pParam(pParam)

{...}

T * get(int key)

{

return m_pParam->get(key);

}

/*其他成员*/

private:

hashtable *m_pParam;

/*其他成员*/

};

主线程将构造好的hashtable传入子线程,这里的子线程对hashtable的操作是只读操作,保证其他线程也不会对hashtable的数据进行修改,所以这里的操作没有加锁。随着需求的变更,现在hashtable中的数据需要支持动态刷新,即之前的参数可能会有变动(数据库中的参数、配置文件信息等),在程序运行中通过发送信号量,由主线程对参数进行重新加载。​通常的做法是,对m_hashParam+互斥锁进行封装,设结构应为SynParam,在操作时上锁:主线程加载参数,lock() -> 读取参数到内存 -> m_hashParam->put(key, value) -> unlock(),重新加载参数时,同样的方式处理。子线程同样保存封装后的结构体SynParam的指针,m_pSynParam,并在操作时,进行加锁保护。这样在程序收到参数刷新的信号量时,主线程对参数进行刷新,而子线程读取到的是最新的数据。注意在子线程中 m_SynParam->get(key)时,同样需要加锁,这样才能保证读取到底数据是正确的,原理等同于一个线程写多个线程读的经典问题。在程序中参数刷新的频率远低于子线程中对参数结构的读取,虽然能够保证参数每次都读取到最新的,但是加锁的代价实在太高,会影响到程序的效率。

现在考虑另一种方式,主线程依然加载数据到内存中,假设加载到hashParam_A中,设 phashParam = &hashParam_A,主线程中创建子线程,将phashParam作为参数传递给子线程,注意,子线程中保存phashParam的地址,m_pphash = &phashParam,即pphash = &(&m_hashParam),在子线程中,获取key值操作表示如: value = (*pphash)->get(key); 这里同样只读操作,并没有加锁:

void loadParam(hashtable & hashParam)

{

//加载参数

return;

}

class ThreadX

{

public:

ThreadX(hashtable *pParam):m_pParam(&pParam)

{...}

/*其他成员*/

T * get(int key)

{

value = (*m_ppParam)->get(key);

}

private:

hashtable **m_ppParam;    //注意这里是二级指针

/*其他成员*/

};

hashtable hashParam_A;

loadParam(hashParam_A);

hashtable * pParam = &hashParam_A;

ThreadX thd(pParam);

在参数刷新时,主线程加载内存到另一个同样的结构体 m_hashParamB中,这时令 pParam = &hashParamB,pParam的值改变了,而子线程中的m_ppParam指向phash,所以*pphash的值也改变了,实际指向hashParamB,即新的内存结构:

hashtable hashParam_B;

loadParam(hashParam_B);

hashtable * pParam = &hashParam_B;

注意phash=&hashParam_B没有加锁的原因是因为在32位的平台,这里是一个原子操作,所以可以保证子线程value = (*m_ppParam)->get(key); 时得到最新的参数值。如果是64位的平台,对pParam = &hashParam_B的指针赋值操作,可能会被分解成2条指令,可能会导致在某个子线程获取value,对*m_ppParam解引用时,*ppParam指向的表示一个错误的地址!

0b1331709591d260c1c78e86d0c51c18.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值