关于同步事件分离器
了解ACE的同学想必都知道它使用了Reactor的设计模式,ACE开发的应用程序中,有个地方会调用eventloop,里面会不停地去轮询。当询到事件时,就将事件分发给指定的事件处理器,事件处理器里面有一些什么handle_read,handle_write之类的函数来响应事件。本程序也借鉴了这种模式,这样使程序结构上变得更加清晰,理解起来也更容易些。
同步事件分离器实现
本程序中的同步分离器基于套接字select函数实现,另外我们还监视定时器事件。
先说select吧,大家都知道select用于等待某个描述就绪,要么可写,要么可读,或者出错,select函数就会返回。为实现这一功能,我们需要两个描述符集,一个读,另外一个写。每次select前都会先清一下描述符集再添加。下面是实现代码:
int CSelectReactor::SelectSocket()
{
ClearFdSet();
AddToFdSet();
int nRet = 0;
timeval tmval;
tmval.tv_sec = 1;
tmval.tv_usec = 0;
nRet = select(m_nMaxSocketFd + 1, &m_rSet, &m_wSet, NULL, &tmval);
if (nRet > 0)
{
vector<ISocket *>::iterator it = m_vecSockets.begin();
for (; it != m_vecSockets.end(); ++it)
{
if (FD_ISSET((*it)->GetHandle(), &m_rSet))
{
int nRes = (*it)->HandleRead();
if (nRes == -1)
{
(*it)->HandleClose();
(*it)->SetReactor(NULL);
(*it)->Close();
continue;
}
}
if (FD_ISSET((*it)->GetHandle(), &m_wSet))
{
int nRes = (*it)->HandleWrite();
if (nRes == -1)
{
(*it)->HandleClose();
(*it)->SetReactor(NULL);
(*it)->Close();
continue;
}
}
}
}
return nRet;
}
当有事件来临时,我们转到相应的事件处理函数,如HandleRead和HandleWrite,事件处理函数里面具体的实现逻辑,后面作详细介绍。
关于定时器事件,是在UpdateTimerList函数中实现的。我们需要维护一个定时器队列,把要监视的事件加入到队列中。时间到了会调用指定pCallback的OnTimer事件处理函数。
void CSelectReactor::UpdateTimerList()
{
list<TimerInfo>::iterator it = m_lstTimerInfo.begin();
for (; it != m_lstTimerInfo.end(); )
{
if (it->bRemove == true)
{
m_lstFreeTimerID.push_back(it->nTimerID);
it = m_lstTimerInfo.erase(it);
continue;
}
if (GetTickCount() >= it->llLastshotTick + it->nInterval)
{
it->pCallback->OnTimer(it->nTimerID);
it->llLastshotTick = GetTickCount();
if(it->bOneShot)
{
m_lstFreeTimerID.push_back(it->nTimerID);
it = m_lstTimerInfo.erase(it);
continue;
}
}
++it;
}
这两件事情都是在另外一个线程中做的,当任务启动时,会创建线程,里面就会做这个事情。
程序源代码下载地址:http://download.youkuaiyun.com/detail/zxywd/9415711