關於信號有關的APUE和SIGALRM信號實例


1 信號基本原理和函數接口

(1)APUE一書中第10章信號

該章節詳細講解了unix系統信號相關的內容,下面這篇文章很好的總結了本章的知識概要,

原文鏈接:http://blog.csdn.net/atfield/article/details/1532506

每小節知識實例參見《APUE》第十章p233~285.

(2)信號的“未決”和“阻塞”

原文鏈接:http://blog.csdn.net/sunyubo458/article/details/4484957

未決”:信號的狀態,從信號產生到信號被處理的一段時間;

阻塞”:阻塞的是信號的處理,不阻塞信號的產生。

信號的阻塞和回覆可通過sigprocmask()接口實現。在信號阻塞到回覆的期間,是信號的未決狀態。

信號經過產生--註冊--註銷--處理的四個階段爲信號的生命週期。

實時信號(可靠信號):每產生一個就向task_struct結構中註冊一個sigquene結構體,註銷的時候根據同一信號的註冊個數進行不同處理,釋放sigquene結構體,且(只有一個,則直接在未決信號集中刪除;有多個,則不刪除)。

非實時信號(不可靠信號):每產生一個就向task_struct結構中註冊一個sigquene結構體,註銷的時候根據同一信號的註冊個數進行不同處理,釋放sigquene結構體,在未決信號集中刪除該信號。

2 SIGALRM信號實例----心跳連接

(1)實例背景

在實現心跳連接時,使用的是setitimer()的定時器函數,定時器守護線程每一段時間發送一個SIGALRM信號,主線程收到此信號進行處理,向對方發送一個心跳報文包,感知和對方網絡連接的狀況(網絡線路故障,對方機器宕機等不正常關閉連接的情況)。

(2)關鍵結構TimerManager

對多併發的連接的處理採用的是EPOLL框架,線程間用管道Pipe進行的通信。系統構造一個全局的定時器管理類對象TimerManager(g_TimerManager),擁有pipe(接收各線程的Timer),pipe[0]讀端綁定爲RecvData()-->RecvTimer()的讀端。在init()時,屏蔽SIGALRM信號,創建定時器線程,線程函數用pthread_procmask()恢復信號,設置定時時間(每一秒鐘查詢m_TimerList中的時鐘是否過期)

 struct itimerval { 
                struct timerval it_interval; 
                struct timerval it_value; 
              }; 
 struct timeval { 
                long tv_sec; 
                long tv_usec; 
              };            
註釋:it_interval爲每經過it_intercal時間久發送一個SIGALRM信號;it_value爲經過該段時間就發送SIGALRM信號(只發一次)。

信號SIGALRM處理函數爲TimerManager.CheckTimeOut()。

        需要定時的時候,初始化對象Timer,調用attachTimer()----->registerThread(),將Timer註冊到TimerManager的m_TimerList中,綁定讀端和寫端到全局Epoll中,將Timer對象包裝寫入m_MsgPipe[1]中。

       線程函數功能:恢復SIGALRM後,死循環從m_MsgPipe[0]讀取TImer Obj,將Timer Obj insert()進TimerList中,再做checkTimeOut()檢查時鐘超時。

      TimerManager維護的成員有:

    int        m_MsgPipe1[2];            //for TimerManager receiving Timers from main thread

    EpollEvent m_EpollEvent;             //EpollEvent Handler
    std::map<pthread_t,int> m_MsgRPipeList;   //綁定的Timer的Epoll的讀端
    std::map<pthread_t,int> m_MsgWPipeList;   //綁定的Timer的Epoll的寫端
    std::multiset<Timer*,LessTimer> m_TimerList;  // 管理的多線程多個定時器鏈表

      CheckTimeOut():將到時的定時器SendTimer(Timer* P)到TimerManager的m_MsgWPipeList[p->getTid()],觸發主線程Epoll的可讀事件,m_MsgRPipeList[p->getTid()],調用RecvData(),取出Timer *P,調用p->DoAction(),實現定時發送心跳報文包的任務。


註釋:1 文中的TimerManage和Epollr源代碼可Pm我獲得。

            2 代碼中設計多重集合的排序,Timer的優先級包裝,與本文探討的定時器信號關係不大,暫不詳解。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章