天天看点

<心跳连接一>关于信号有关的APUE和SIGALRM信号实例 1 信号基本原理和函数接口2 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的优先级包装,与本文探讨的定时器信号关系不大,暂不详解。

继续阅读