統一事件源簡介

服務器編程中通常有三大類事件需要處理,一類是I/O事件,一類是信號事件,一類是時間事件。
信號事件是一種異步事件,當信號來臨時,主邏輯會被打斷去執行信號處理函數。而信號到來的時機是不確定,如果此時信號處理函數會去訪問一個已經被鎖住的資源,那麼這個線程就會被阻塞。所以信號處理函數應該是可重入的。
一般信號處理時會將一些信號屏蔽,爲了不屏蔽這些信號太久,同時也不至於主邏輯被衝散,一種解決方案是:信號處理函數只是簡單的通知主循環(用於處理I/O事件)並告訴信號值,真正的信號處理邏輯被主循環調用,根據信號值做出相應的處理。信號處理函數和主循環之間通常用管道做通信。信號處理函數從管道的寫端寫入信號值,主循環從管道的讀端讀取信號值。因爲主循環本身就要利用I/O複用函數監聽鏈接進來的socket,所以將這個管道一併註冊進I/O複用函數就能在主循環中及時得到信號到來的通知。

int pipefd[2];
... 
void sig_handler(int sig)  
{  
    int save_errno = errno;  
    int msg = sig;  
    send(pipefd[1], (char*)&msg, 1, 0);//將信號按字節寫入管道,以通知主循環
    errno = save_errno;  
} 

void addsig(int sig)  
{  
    struct sigaction sa;  
    memset(&sa, '\0', sizeof(sa));  
    sa.sa_handler = sig_handler;  
    sa.sa_flags |= SA_RESTART; //信號如果打斷了慢速系統調用,中斷處理完成之後繼續恢復系統調用
    sigfillset(&sa.sa_mask);//在信號處理函數中屏蔽所有信號
    assert(sigaction(sig, &sa, NULL) != -1);  
}  

void handle_sig(int sig)
{
    switch(sig)
    {
        case SIGCHLD:
            ...
        case SIGHUP:
            ...
        case SIGTERM:
            ...
        case SIGINT:
            ...
        ...
    }
}
...

int main(int argc, char **argv)
{
    ...
    ret=socketpair(PF_UNIX,SOCK_STREAM,0,pipefd);   
    setnonblocking(pipefd[1]);  
    addfd(epollfd,pipefd[0]);  
    while(true)
    {
        int ret = epoll_wait(epollfd, events, MAX_EVENTS, -1);
        for (int i = 0; i < ret; i++)
        {
            if(events[i].fd == pipefd[0] && events[i].events & EPOLLIN) //接收到信號
            {
                char signals[1024];  
                int num = recv(pipefd[0], signals, sizeof(signals), 0);  
                if (num == -1)  
                    continue;  
                else if (num == 0)  
                    continue;  
                else 
                {  
                    //每個信號值佔1字節,所以按字節來逐個接收信號  
                    //可能處理的時候收到了多個信號
                    for (int i = 0; i < num; i++) 
                    {
                        handle_sig(signals[i]);
                    } 
                }
            }
        }
    }
    ...
}

參考資料
《Linux高性能服務器編程》
http://www.2cto.com/os/201109/104474.html
http://blog.csdn.net/jasonliuvip/article/details/23305297

發佈了38 篇原創文章 · 獲贊 27 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章