首页 > 代码库 > 使用二级指针在多线程进行刷新操作

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

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

//用hashtable保存程序运行所需的参数hashtable<key, value> hashParam;void loadParam(hashtable<key, value> & hashParam){    //加载参数    return;}//模拟线程类class ThreadX{public:    ThreadX(hashtable<key, value> *pParam):m_pParam(pParam)    {...}
   T * get(int key)
   {
     return m_pParam->get(key);
   }
/*其他成员*/private: hashtable<key, value> *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 = http://www.mamicode.com/(*pphash)->get(key); 这里同样只读操作,并没有加锁:

void loadParam(hashtable<key, value> & hashParam){    //加载参数    return;}class ThreadX{public:    ThreadX(hashtable<key, value> *pParam):m_pParam(&pParam)    {...}    /*其他成员*/    T * get(int key)    {        value = (*m_ppParam)->get(key);    }private:    hashtable<key, value> **m_ppParam;    //注意这里是二级指针    /*其他成员*/};hashtable<key, value> hashParam_A;loadParam(hashParam_A);hashtable<key, value> * pParam = &hashParam_A;ThreadX thd(pParam);

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

hashtable<key, value> hashParam_B;loadParam(hashParam_B);hashtable<key, value> * pParam = &hashParam_B;

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

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