读书人

心跳包的线程同步有关问题

发布时间: 2012-01-23 21:57:28 作者: rapoo

心跳包的线程同步问题
本人的心跳包处理是这么设计的,在启动程序后,立刻开启一个心跳线程,专门用于处理客户的连接。这个线程用于处理所有的客户端的连接,当线程没有接到其中一个客户发来的请求达到20秒,即认为掉线。客户连接时,发送了一次数据之后,立刻退出。
为了保证定时处理,启动了可等待定时器与事件机制。
1.心跳线程是这么启动的:
HANDLE hHeatBeat=CreateThread(NULL,0,CHeartBeat::WaitProc,NULL,0,NULL);
CloseHandle(hHeatBeat);

2.心跳包的主线程

C/C++ code
DWORD CALLBACK CHeartBeat::WaitProc(LPVOID lpVoid){         HANDLE          hTimer;    BOOL            bSuccess;    __int64         qwDueTime;    LARGE_INTEGER   liDueTime;    char           szError[255];           DWORD          dwResult;        HANDLE*  phTimers=NULL,*phEvents=NULL;        while(true)    {        if(hbList.size()>0)        {            //manage events            phEvents=(HANDLE*)LocalAlloc(LPTR|LMEM_ZEROINIT,sizeof(HANDLE)*hbList.size());            for(vector<CHeartBeat*>::size_type i=0;i<hbList.size();++i)            {                if(hbList[i]->m_hEvent!=NULL)                    phEvents[i]=hbList[i]->m_hEvent;            }            //wait for one of event become signal, if there are no events become sigal,after 500 millisecond, it return            dwResult=WaitForMultipleObjects((DWORD)hbList.size(),phEvents,FALSE,500);            if(dwResult>=WAIT_OBJECT_0 && dwResult<=WAIT_OBJECT_0+hbList.size()-1)            {                vector<CHeartBeat*>::iterator iter=hbList.begin();                for (;iter!=hbList.end();++iter)                {                    if((*iter)->m_hEvent==phEvents[dwResult-WAIT_OBJECT_0])                    {                        if((*iter)->m_hTimer!=NULL)                        {                            //when follow MCT health messages was recevied                            CancelWaitableTimer((*iter)->m_hTimer);                            bSuccess = SetWaitableTimer(                                (*iter)->m_hTimer,           // Handle to the timer object                                &liDueTime,       // When timer will become signaled                                1200000,             // Periodic timer interval of 2 seconds                                NULL,                                NULL,                                FALSE );          // Do not restore a suspended system                            if (! bSuccess )                             {                                sprintf( szError, "SetWaitableTimer failed with Error \                                                  %d.\n", GetLastError() );                                cout<<szError<<endl;                                CloseHandle( hTimer );                                return false;                            }                                                    }                        else                        {                            if ( hTimer = CreateWaitableTimer(                                NULL,                   // Default security attributes                                FALSE,                  // Create auto-reset timer                                NULL ) )           // Name of waitable timer                            {                                // Create an integer that will be used to signal the timer                                 // 120 seconds from now.                                qwDueTime = -20 * _SECOND;                                // Copy the relative time into a LARGE_INTEGER.                                liDueTime.LowPart  = (DWORD) ( qwDueTime & 0xFFFFFFFF );                                liDueTime.HighPart = (LONG)  ( qwDueTime >> 32 );                                bSuccess = SetWaitableTimer(                                    hTimer,           // Handle to the timer object                                    &liDueTime,       // When timer will become signaled                                    1200000,             // Periodic timer interval of 120 seconds                                    NULL,                                    NULL,                                    FALSE );          // Do not restore a suspended system                                if (! bSuccess )                                 {                                    sprintf( szError, "SetWaitableTimer failed with Error \                                                      %d.\n", GetLastError() );                                    cout<<szError<<endl;                                    CloseHandle( hTimer );                                    return false;                                }                                (*iter)->m_hTimer=hTimer;                            }                             else                             {                                sprintf( szError, "CreateWaitableTimer failed with Error \                                                  %d.\n", GetLastError() );                                cout<<szError<<endl;                                return false;                            }                        }                        ResetEvent((*iter)->m_hEvent);                    }                }            }            else if(dwResult==WAIT_FAILED)            {                OutputDebugString(_T("wait event singal failed\n"));            }            LocalFree((HLOCAL)phEvents);            //manage waitable timers             phTimers=(HANDLE*)LocalAlloc(LPTR|LMEM_ZEROINIT,sizeof(HANDLE)*(hbList.size()));                       for(vector<CHeartBeat*>::size_type i=0;i<hbList.size();++i)            {                if(hbList[i]->m_hTimer!=NULL)                    phTimers[i]=hbList[i]->m_hTimer;            }                        //wait for one of event become signal, if there are no events become sigal,after 500 millisecond, it return            DWORD dwResult=WaitForMultipleObjects((DWORD)(hbList.size()),phTimers,FALSE,500);            if(dwResult>=WAIT_OBJECT_0 && dwResult<=WAIT_OBJECT_0+hbList.size()-1)            {                //a client is power off                vector<CHeartBeat*>::iterator iter=hbList.begin();                int i=0;                for (;iter!=hbList.end();++iter)                {                    i++;                    if((*iter)->m_hTimer==phTimers[dwResult-WAIT_OBJECT_0])                    {                        CHeartBeat* phb=(*iter);                        char mbProjNum[1024];                        strcpy(mbProjNum,phb->m_strProj);                        printf("\na power off event occuered on ProjNum:%s\n",mbProjNum);                        //before remove element, clear event and timer                        SetEvent((*iter)->m_hEvent);                        WaitForSingleObject((*iter)->m_hEvent,INFINITE);                        CloseHandle((*iter)->m_hEvent);                        CloseHandle((*iter)->m_hTimer);                        //remove element                        hbList.erase(iter);                        break;                    }                }            }                                    LocalFree((HLOCAL)phTimers);                            }                //#region 1        //heart beat thread will exist        if(WaitForSingleObject(m_hExitHandle,500)==WAIT_OBJECT_0)        {            if(hbList.size()>0)            {                vector<CHeartBeat*>::iterator iter=hbList.begin();                for(;iter!=hbList.end();++iter)                {                    CHeartBeat* pHB=(CHeartBeat*)(*iter);                    if(pHB->m_hEvent!=NULL)                    {                        CloseHandle(pHB->m_hEvent);                        SetEvent(pHB->m_hEvent);                        WaitForSingleObject(pHB->m_hEvent,INFINITE);                    }                    if(pHB->m_hTimer!=NULL)                     {                        CancelWaitableTimer(pHB->m_hTimer);                        CloseHandle(pHB->m_hTimer);                    }                    SAFE_DELETE(pHB);                }                hbList.clear();                break;            }                    }                //#endregion    }    return true;} 



3.当有客户连接时,向心跳线程发送事件信号,对于客户每一次连接,服务端会创建一个心跳包对象,将其加入列表,而当客户后序连接时,服务端仅设置指定的事件信号
C/C++ code
 bool bExist=false;    CHeartBeat* pHeartBeat=NULL;    for(vector<CHeartBeat*>::iterator iter=hbList.begin();        iter!=hbList.end();        ++iter)    {        if(strcmp((*iter)->GetProjNum(),pMessageInfo->msg_base_info.szPlanNumber)==0)        {            //IM has received health message previous for special plannumber            bExist=true;            pHeartBeat=*iter;            break;        }    }    if(bExist)    {        //notify CHeartBeat to reset waitable timer        if(pHeartBeat!=NULL) SetEvent(pHeartBeat->GetEventHandle());        return true;    }    else    {        CHeartBeat* pHeart=new CHeartBeat();        //notify CHeartBeat to create waitable timer        if(!pHeart->Start(pMessageInfo->msg_base_info.szPlanNumber))        {            SAFE_DELETE(pHeart);            return false;        }        hbList.push_back(pHeart);        return true;    }    return true;


3.以下是CHeartBeat类的Start方法:
C/C++ code
bool  CHeartBeat::Start(const char* projNum){    HANDLE handle;    handle=CreateEvent(NULL,TRUE,FALSE,NULL);       if(handle==NULL)    {        return false;            }    m_hEvent=handle;    SetEvent(m_hEvent);    strcpy(m_strProj,projNum);    return true;}


4.当有服务端结束时,等待心跳线程退出
HANDLE hExitHeartBeat=CreateEvent(NULL,TRUE,TRUE,NULL);
CHeartBeat::SetExitEvent(hExitHeartBeat);
WaitForSingleObject(hHeatBeat,INFINITE);, (1)
对于心跳线程的退出处理用代码段2中的region 1

请问各位大侠,为什么当服务端运行到WaitForSingleObject(hHeatBeat,INFINITE)时,这个函数无法返回,而且心跳线程明明可以已经退出了。
当把语句(1)修改成WaitForSingleObject(hHeatBeat,1000);时
程序有时候会内存泄露?

[解决办法]
mark

C/C++学习交流
欢迎热爱C/C++的人士加入群 72837978 一起来交流学习吧
欢迎热爱C/C++的人士加入群 72837978 一起来交流学习吧
欢迎热爱C/C++的人士加入群 72837978 一起来交流学习吧
欢迎热爱C/C++的人士加入群 72837978 一起来交流学习吧
[解决办法]
CloseHandle只能是将句柄关闭,不能将线程直接终止。
另外对于线程的终止最好是让它自己主动终止,不要通过外界的管理程序去强制终止。如可能一个状态变量来控制,每次在循环执行之间先状态这个状态变量,通过状态变量决定是否要终止。外界只需要改变这个变量的值即可。
while(m_Run)
{
........;
sleep(100);
}
//外界控制是只需要调用下面一行代码那可
m_Run = false;

读书人网 >VC/MFC

热点推荐