利用主动对象模型设计并发同步请求

我们可以利用主动对象调用和执行去耦合的这种方式,实现自己的并发同步请求,这样可以防止服务程序和消费者之间的请求阻塞,并能提高处理性能。

基本的解决方案:

l         请求接口(proxy):用于接收客户端的请求数据;

l         执行体(servant):用来实现具体的执行过程;

l         调度(task):用于多线程和队列结合实现请求派发;

交互序列图:
   
下面为演示程序:

请求结构文件,实现请求结构继承和操作:

文件名:pdu.hpdu.inl

#ifndef __PDU_INCLUDE

#define __PDU_INCLUDE

 

#include "ace/Semaphore.h"

#include "ace/Atomic_Op.h"

#include "servant.h"

 

class CPduException

{

public:

         CPduException(int n) : _Err(n) {}

         int _Err;

};

 

/***********************************

 * 数据包基类

 * 通过继承的方法,实现类型无关

 **********************************/

class CPduBase

{

public:

         CPduBase():_nRef(1){}

         virtual bool Guard() const = 0;

         virtual void Call() = 0;

         void AddRef(){_nRef++;}

         void Release()

         {

                   _nRef--;

                   if (_nRef.value() == 0)

                            delete this;

         }

private:

         ACE_Atomic_Op<ACE_Thread_Mutex, long> _nRef;

};

/**********************************

 *请求PDU,通过模板实现请求数据无关

 *********************************/

template<class ITEM>

class CRequestPdu : public CPduBase

{

public:

         CRequestPdu(const ITEM & item) : _Item(item){}

         bool Guard() const;

         void Call();

private:

         ITEM _Item;

};

/*********************************

 *回应PDU

 *通过模板可以返回不同类型的回应数据包

 ********************************/

template<class ITEM>

class CResponsePdu : public CPduBase

{

public:

         CResponsePdu(int nTimeout)

                   : _nTimeout(nTimeout),

                   _semLock(0) {}

         operator ITEM() throw(CPduException);

         bool Guard() const;

         void Call();

private:

         int _nTimeout;

         ACE_Semaphore _semLock;

         ITEM _Item;   //结果

};

 

#include "pdu.inl"

#endif

 

template<class ITEM>

void CRequestPdu<ITEM>::Call()

{

         CServant::instance()->Put(_Item);

}

 

template<class ITEM>

bool CRequestPdu<ITEM>::Guard() const

{

         return !CServant::instance()->Full();

}

/*****************************************

 * 请求回应类

 ****************************************/

template<class ITEM>

void

CResponsePdu<ITEM>::Call()

{

         _Item = CServant::instance()->Get();

         _semLock.release ();

}

template<class ITEM>

bool

CResponsePdu<ITEM>::Guard() const

{

         return !CServant::instance()->Empty();

}

template<class ITEM>

CResponsePdu<ITEM>::operator ITEM()

throw(CPduException)

{

         ACE_Time_Value t(nTimeout, 0);

         if (-1 == _semLock.acquire (t) )

                   throw CPduException(ETIME);

         return _Item;

}

 

代理源代码:实现请求转换

文件名:proxy.h

#ifndef __PROXY_INCLUDE

#define __PROXY_INCLUDE

 

#include "servant.h"

#include "pdu.h"

 

class CScheduler;

/*

 *     代理,把客户的请求数据转换成请求数据包

 */

class CProxy

{

public:

         CProxy(CScheduler* p) : _pScheduler(p) {}

         CResponsePdu<STResponse>* Call(const STRequest & obj);

private:

ACE_Thread_Mutex _Mutex;

         CScheduler * _pScheduler;

};

#endif

 

文件名:proxy.cpp

 

#include "proxy.h"

#include "Scheduler.h"

 

CResponsePdu<STResponse>* CProxy::Call(const STRequest & obj)

{

         CRequestPdu<STRequest> * pRequest = new CRequestPdu<STRequest>(obj);

         CResponsePdu<STResponse> * pResp   = new CResponsePdu<STResponse>(10);

 

         ACE_Guard<ACE_Thread_Mutex> guard(_Mutex);

         _pScheduler->putq(pRequest);

         pResp->AddRef();

         _pScheduler->putq(pResp);

         return pResp;

}

调度模块:实现多线程并发处理请求

文件名:scheduler.h

#ifndef __SCHEDULER_INCLUDE

#define __SCHEDULER_INCLUDE

 

#include "pdu.h"

#include "ace/Task_Ex_T.h"

 

class CScheduler : public ACE_Task_Ex<ACE_MT_SYNCH, CPduBase>

{

public:

         int open(void*);

         int svc(void);

         int SetExit();

};

#endif

 

文件名:scheduler.cpp

#include "scheduler.h"

 

int CScheduler::open(void*)

{

         activate (THR_NEW_LWP, 1);

         return 0;

}

/*

 *     多线程实现并发处理

 */

int CScheduler::svc()

{

         CPduBase * pPdu = NULL;

         while (1) {

                   getq(pPdu);

                   if ((CPduBase*)-1 == pPdu)

                            break;

                   //如果服务程序可以继续处理,则调用call方法, 否则丢弃

                   if (pPdu->Guard())

                            pPdu->Call();

                   pPdu->Release();

                   Sleep(1);

         }

         return 0;

}

 

/*

 *     使线程退出,停止服务

 */

int CScheduler::SetExit()

{

         for (int i = 0; i < THREAD_NUMS; i++)

                   putq((CPduBase*)-1);

         wait();

         return 0;

}

执行体:具体进行执行的类

文件名:servant.h

#ifndef __SERVANT_INCLUDE

#define __SERVANT_INCLUDE

 

#include "ace/Singleton.h"

#include <list>

 

struct STRequest

{

         char _ch[127];

         STRequest & operator = (const STRequest& obj)

         {

                   strcpy (_ch, obj._ch);

                   return *this;

         }

};

struct STResponse

{

         char _chResult[127];

         STResponse& operator = (const STResponse & obj)

         {

                   strcpy (_chResult, obj._chResult);

                   return *this;

         }

};

/********************************

 * 具体的执行类

 *******************************/

class CServantT

{

public:

         friend class ACE_Singleton<CServantT, ACE_Thread_Mutex>;

 

         void Put(const STRequest &);

         STResponse Get();

         bool Empty ();

         bool Full();

private:

         CServantT(){}

         ACE_Thread_Mutex     _Mutex;

         std::list<STRequest> _lstItems;

};

 

typedef ACE_Singleton<CServantT, ACE_Thread_Mutex> CServant;

 

#endif

 

文件名:servant.cpp

#include "servant.h"

 

 

void CServantT::Put(const STRequest & item)

{

         ACE_Guard<ACE_Thread_Mutex> guard(_Mutex);

         this->_lstItems.push_back (item);

}

 

STResponse CServantT::Get()

{

         STResponse req;

 

         ACE_Guard<ACE_Thread_Mutex> guard(_Mutex);

         STRequest item = *(this->_lstItems.begin ());

         strcpy (req._chResult, item._ch);

         this->_lstItems.pop_front();

         return req;

}

 

bool CServantT::Empty ()

{

         return this->_lstItems.empty();

}

 

bool CServantT::Full()

{

         return this->_lstItems.size() >= 10;   //只能放入10个元素,仅做测试用

}

 

主程序:用于测试,用多线程模拟多客户端,并检验请求和结果是否正确。

#include "ace/ace.h"

#include "proxy.h"

#include "scheduler.h"

 

/*

 *     模拟多客户测试整个系统

 */

class CClient : public ACE_Task<ACE_MT_SYNCH>

{

public:

         CClient (CProxy * proxy)

                   : _Proxy(proxy), _bRun(0) {}

         int open(void*)

         {

                   activate(THR_NEW_LWP, 8);

                   _bRun = 1;

                   return 0;

         }

         int svc(void)

         {

                   STRequest obj;

                   long n = 0;

                   while(_bRun) {

                            sprintf(obj._ch, "客户:%d,第%d次请求/n", ACE_Thread::self(), n++);

                            try {

                                     CResponsePdu<STResponse>* pResp = _Proxy->Call(obj);

                                     STResponse tResp = *pResp;

                                     //比较请求和回应是否正确

                                     if (strcmp(obj._ch, tResp._chResult) != 0 )

                                               ACE_DEBUG((LM_DEBUG, "请求和回应不匹配:%s", tResp._chResult));

                                     pResp->Release();

                            } catch (CPduException &e) {

                            }

                           

                            Sleep(1);

                   }

                   return 0;

         }

         void SetExit()

         {

                   _bRun = 0;

                   wait();

         }

private:

         bool     _bRun;

         CProxy * _Proxy;

};

int main(int argc, char ** argv)

{

         ACE::init();

 

         CScheduler server;

         CProxy     proxy(&server);

         CClient    cli(&proxy);

         server.open(0);  //启动服务进行并发处理

         cli.open(0);    //开始启动多客户模拟

 

         getchar();   //任意键

         //退出

         cli.SetExit();

         server.SetExit();

 

         ACE::fini();

         return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值