我们可以利用主动对象调用和执行去耦合的这种方式,实现自己的并发同步请求,这样可以防止服务程序和消费者之间的请求阻塞,并能提高处理性能。
基本的解决方案:
l 请求接口(proxy):用于接收客户端的请求数据;
l 执行体(servant):用来实现具体的执行过程;
l 调度(task):用于多线程和队列结合实现请求派发;
![](https://p-blog.csdn.net/images/p_blog_csdn_net/lgqzlx/active.bmp)
请求结构文件,实现请求结构继承和操作:
文件名:pdu.h和pdu.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;
}