• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

            服務器公共庫開發--定時器管理器模塊

            在寫定時器管理器時,參考了幾篇博文:
            1)【原創】技術系列之 定時器(一)
            2) libevent 源碼分析:min_heap帶來的超時機制

            最后決定采用<<用TCP/IP進行網際互連>>第二卷中講述TCP定時器一章中的策略, 使用一個定時器鏈表, 根據定時器觸發的時間的升序排列, 每個定時器中有一個字段存放距離鏈表中上一個定時器觸發之后的相對時間值.這樣, 每次定時器到時的時候, 都去查詢定時器鏈表的第一個節點, 如果沒有到觸發時間就直接返回;否則就依次遍歷該鏈表, 查看哪些定時器是可以觸發的, 觸發定時器事件之后將這些定時器從鏈表中取出, 然后重新插入到定時器鏈表中, 并且更新相對時間字段.這個實現想法很簡單,但是實現的時候有不少細節需要考慮,我折騰了兩天在調試!!-_-.

            另外,這個定時器管理器也是一個單件.

            我的這個實現還是有局限性的:
            1) 每個定時器有一個ID, 定時器與ID一一對應, 在定時器中有一個字段保存當前分配的ID計數, 每新增一個定時器就加一, 但是刪除定時器卻不回收.這個字段是int型, 我想應該沒有哪個系統會加入這么多定時器以至于溢出吧.
            2) 采用setitimer進行定時, 每次觸發生成ALARM信號, 這要求在使用這個定時器的時候注意處理被信號中斷的情況(比如收發網絡數據時).在參考的第一篇博文中, 采用的是生成一個新的線程, 專門處理定時操作, 使用的是select函數, 但是我認為如果這樣的話, 那么就用在代碼中注意多線程安全,這對于我這種基本不寫多線程服務器的人來說是個噩夢....
            3)目前只做到精確到秒,不過,對我來說也夠用了.

            timermanager.h:
            /********************************************************************
                created:    2008/08/10
                filename:     timermanager.h
                author:        Lichuang
                            
                purpose:    定時器管理器
            ********************************************************************
            */

            #ifndef __TIMER_MANAGER_H__
            #define __TIMER_MANAGER_H__

            #include 
            "singleton.h"
            #include 
            "threadmutex.h"
            #include 
            <map>
            #include 
            <list>
            #include 
            <signal.h>

            using namespace std;

            enum ETimeEventType
            {
                TIMER_ONCE 
            = 0,             //一次型
                TIMER_CIRCLE                //循環型
            };

            struct TTimeEvent
            {
                
            int nId;                    // 定時器ID
                int nInterval;              // 定時器時間間隔(秒)
                int nSecondsLeft;           // 相對定時器鏈表中前一個節點觸發后的相對時間(秒)
                ETimeEventType nType;       // 事件類型
                void (*pFn)(void* pArg);    // 回調函數
                void* pArg;                 // 回調函數參數
            };

            class CTimerManager
                : 
            public CSingleton<CTimerManager>
            {
            public:
                
            int Init(int nInterval);

                
            int AddTimer(TTimeEvent& tTimeEvent);
                
            int DelTimer(int nId);

                
            void PrintTimerList();

                
            int Start();
                
            int Stop();

                
            int Process();
            private:
                CTimerManager();
                
            virtual ~CTimerManager();

            private:
                
            int SetTimer(sighandler_t pFn);
                
            int AddTimer(list<TTimeEvent>::iterator& tPos, TTimeEvent& tTimeEvent, bool bIsNewEvent);

            private:
                
            int m_nInterval;        
                unsigned 
            int m_nIdCount;
                list
            <TTimeEvent> m_lEvent;

                DECLARE_SINGLETON_CLASS(CTimerManager)    
            };

            #endif /* __TIMER_MANAGER_H__ */



            timermanager.cpp:
            /********************************************************************
                created:    2008/08/10
                filename:     timermanager.cpp
                author:        Lichuang
                            
                purpose:    定時器管理器
            ********************************************************************
            */

            #include 
            "timermanager.h"
            #include 
            <sys/time.h>

            static void Process(int nSigNo);

            CTimerManager::CTimerManager()
                : m_nInterval(
            0)
                , m_nIdCount(
            0)      
            {
            }

            CTimerManager::
            ~CTimerManager()
            {
            }

            int CTimerManager::AddTimer(TTimeEvent& tTimeEvent)
            {
                list
            <TTimeEvent>::iterator Iter1 = m_lEvent.begin();
                
            return AddTimer(Iter1, tTimeEvent, true);
            }

            int CTimerManager::DelTimer(int nId)
            {
                list
            <TTimeEvent>::iterator Iter1 = m_lEvent.begin(), Iter2 = m_lEvent.end();
                
            for (; Iter1 != Iter2; ++Iter1)
                {
                    
            if (Iter1->nId == nId)
                    {
                        
            break;
                    }
                }
                
            if (Iter1 == Iter2)
                {
                    
            return -1;
                }

                
            int nSecondsLeft = Iter1->nSecondsLeft;
                Iter2 
            = Iter1;
                
            ++Iter2;
                m_lEvent.erase(Iter1);
                
            // 刪除一個定時器還要更新下一個節點(如果存在的話)的相對時間
                if (m_lEvent.end() != Iter2)
                {
                    Iter2
            ->nSecondsLeft += nSecondsLeft;
                }

                
            return 0;
            }

            void CTimerManager::PrintTimerList()
            {
                list
            <TTimeEvent>::iterator Iter1 = m_lEvent.begin(), Iter2 = m_lEvent.end();
                
            for (; Iter1 != Iter2; ++Iter1)
                {
                    printf(
            "id = %d, interval = %d, secondleft = %d\n", Iter1->nId, Iter1->nInterval, Iter1->nSecondsLeft);
                }
            }

            int CTimerManager::Start()
            {
                
            return SetTimer(::Process);
            }

            int CTimerManager::Stop()
            {
                m_nInterval 
            = 0;
                
            return SetTimer(SIG_DFL);
            }

            int CTimerManager::Init(int nInterval)
            {
                m_nInterval 
            = nInterval;

                
            return 0;
            }

            int CTimerManager::SetTimer(sighandler_t pFn)
            {
                
            struct itimerval interval;
                    
                interval.it_interval.tv_sec 
            = m_nInterval;
                interval.it_interval.tv_usec 
            = 0;
                interval.it_value.tv_sec 
            = m_nInterval;
                interval.it_value.tv_usec 
            = 0;

                
            if (0 != ::setitimer(ITIMER_REAL, &interval, NULL)) 
                {
                    
            return -1;
                }    

                
            if (0 != ::signal(SIGALRM, pFn))
                {
                    
            return -1;
                }

                
            return 0;
            }

            int CTimerManager::AddTimer(list<TTimeEvent>::iterator& tPos, TTimeEvent& tTimeEvent, bool bIsNewEvent)
            {
                
            // 根據觸發時間的升序排列, 將定時器放在鏈表的合適位置
                list<TTimeEvent>::iterator Iter1 = tPos, Iter2 = m_lEvent.end();
                
            int nSecondsLeft = 0;
                
            for (; Iter1 != Iter2; nSecondsLeft += Iter1->nSecondsLeft, ++Iter1)
                {
                    
            if (Iter1->nSecondsLeft + nSecondsLeft > tTimeEvent.nInterval)
                    {
                        
            break;
                    }
                }

                tTimeEvent.nSecondsLeft 
            = tTimeEvent.nInterval - nSecondsLeft;
                
            // 如果插入節點不是定時器鏈表的最后一個節點, 那么要修改它下一個節點的相對時間值
                if (Iter1 != Iter2)
                {
                    Iter1
            ->nSecondsLeft = Iter1->nSecondsLeft - tTimeEvent.nSecondsLeft;
                }
                
            if (bIsNewEvent)
                {
                    tTimeEvent.nId 
            = m_nIdCount++;
                }

                m_lEvent.insert(Iter1, tTimeEvent);

                
            return tTimeEvent.nId;
            }

            int CTimerManager::Process()
            {
                
            // 如果定時器鏈表是空的, 立即返回
                if (m_lEvent.empty())
                {
                    
            return 0;
                }

                
            // 如果定時器鏈表的頭結點沒有到該觸發的時間, 更新已經過去的時間計數器后返回
                list<TTimeEvent>::iterator Iter1 = m_lEvent.begin();
                Iter1
            ->nSecondsLeft -= m_nInterval;
                
            if (0 < Iter1->nSecondsLeft)
                {
                    
            return 0;
                }

                
            // 定時器鏈表的頭結點已經可以觸發, 從頭結點開始遍歷鏈表, 看看哪些結點也可以觸發事件的
                list<TTimeEvent>::iterator Iter2 = m_lEvent.end();
                list
            <TTimeEvent> lEvent;
                
            while (Iter1 != Iter2)
                {
                    
            if (0 >= Iter1->nSecondsLeft)
                    {
                        
            // 觸發定時事件
                        Iter1->pFn(Iter1->pArg);
                        
            if (TIMER_CIRCLE == Iter1->nType)
                        {
                            lEvent.push_back(
            *Iter1);
                        }
                        
            ++Iter1;
                        m_lEvent.pop_front();
                    }
                    
            else
                    {
                        
            break;
                    }
                }

                
            // 將本次觸發的定時器事件重新插入到定時器鏈表中
                
            // 這里有一個優化策略: nLastInterval 保存上一個重新插入到定時器鏈表中的時間間隔
                
            // 如果這個值比當前節點的時間間隔小, 那么從上一個插入的位置開始搜索
                
            // 否則從定時器節點的開始位置搜索
                int nLastInterval = 0;
                list
            <TTimeEvent>::iterator Iter3;
                
            for (Iter1 = lEvent.begin(), Iter2 = lEvent.end(); Iter1 != Iter2; nLastInterval = Iter1->nInterval, ++Iter1)
                {
                    
            if (0 == nLastInterval || nLastInterval > Iter1->nInterval)
                    {
                        Iter3 
            = m_lEvent.begin();
                    }

                    AddTimer(Iter3, 
            *Iter1, false);
                }

                
            return 0;
            }

            void Process(int nSigNo)
            {
                
            if (nSigNo == SIGALRM)
                {
                    CTimerManager::GetInstance()
            ->Process();
                }
            }



            posted on 2008-08-13 15:36 那誰 閱讀(2940) 評論(2)  編輯 收藏 引用 所屬分類: 服務器設計 、Linux/Unix

            評論

            # re: 服務器公共庫開發--定時器管理器模塊  回復  更多評論   

            比較猥瑣.. 你參考一下ACE吧. perfect

            你要做服務器編程.不可能總是避諱多線程環境. 嘗試一下select吧.
            2008-08-14 09:43 | bugs_killer

            # re: 服務器公共庫開發--定時器管理器模塊[未登錄]  回復  更多評論   

            @bugs_killer
            select我當然有用,只是不用多線程罷了.我寫的服務器都是多進程+多路復用IO的模式.

            2008-08-14 10:21 |
            国产精品免费久久| 狠狠色丁香婷婷综合久久来| 欧美亚洲国产精品久久蜜芽| 国产A级毛片久久久精品毛片| 久久久久一级精品亚洲国产成人综合AV区| 国产亚洲精午夜久久久久久| 国内精品久久国产| 国产激情久久久久影院小草| 午夜视频久久久久一区| 久久精品国产亚洲欧美| 久久99热这里只有精品66| 久久精品国产影库免费看 | 久久综合九色综合久99| 色播久久人人爽人人爽人人片aV| 久久久噜噜噜久久熟女AA片| 久久久久亚洲av成人无码电影| 亚洲成色WWW久久网站| 精品久久人人做人人爽综合| 精品久久久无码人妻中文字幕豆芽 | 91性高湖久久久久| 久久综合国产乱子伦精品免费| 国产精品99久久不卡| 亚洲国产一成人久久精品| 伊人久久大香线蕉综合网站| 久久国产精品免费一区二区三区| 俺来也俺去啦久久综合网| 99久久国产精品免费一区二区 | 人妻无码αv中文字幕久久琪琪布| 狠狠色婷婷综合天天久久丁香| 色欲综合久久躁天天躁蜜桃| 久久午夜福利无码1000合集| 亚洲国产精品无码久久青草| 久久人人爽人人爽人人片AV东京热| 99久久综合狠狠综合久久| 91精品国产高清久久久久久91| 国产精品久久久久天天影视| 国内精品久久久久伊人av| 精品久久久久久| 国产精品久久久久一区二区三区| 国产高潮久久免费观看| 久久久久久亚洲精品不卡|