青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

xiaoguozi's Blog
Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習(xí)慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預(yù)料,人們需要更細(xì)心的觀察別人,要隨時(shí)注意才能保護(hù)別人,因?yàn)樗麄兾幢刂雷约阂裁础ぁぁぁぁ?/span>

一 信號(hào)的種類

可靠信號(hào)與不可靠信號(hào), 實(shí)時(shí)信號(hào)與非實(shí)時(shí)信號(hào)

可靠信號(hào)就是實(shí)時(shí)信號(hào), 那些從UNIX系統(tǒng)繼承過來的信號(hào)都是非可靠信號(hào), 表現(xiàn)在信號(hào)

不支持排隊(duì),信號(hào)可能會(huì)丟失, 比如發(fā)送多次相同的信號(hào), 進(jìn)程只能收到一次. 信號(hào)值小于

SIGRTMIN的都是非可靠信號(hào).

非可靠信號(hào)就是非實(shí)時(shí)信號(hào), 后來, Linux改進(jìn)了信號(hào)機(jī)制, 增加了32種新的信號(hào), 這些信

號(hào)都是可靠信號(hào), 表現(xiàn)在信號(hào)支持排隊(duì), 不會(huì)丟失, 發(fā)多少次, 就可以收到多少次. 信號(hào)值

位于 [SIGRTMIN, SIGRTMAX] 區(qū)間的都是可靠信號(hào).

 

關(guān)于可靠信號(hào), 還可以參考WIKI的一段話:

 

Text代碼  收藏代碼
  1. The real-time signals, ranging from SIGRTMIN to SIGRTMAX, are a set of signals that can be used for application-defined purposes.  
  2. Because SIGRTMIN may have different values on different Unix-like systems, applications should always refer to the signals in the form SIGRTMIN+n, where n is a constant integer expression.  
  3. The real-time signals have a number of properties that differentiate them from other signals and make them suitable for application-defined purposes:  
  4. * Multiple instances of a real-time signal can be sent to a process and all will be delivered.  
  5. * Real-time signals can be accompanied by an integer or pointer value (see sigqueue[2]).  
  6. * Real-time signals are guaranteed to be delivered in the order they were emitted.  
 


命令行輸入 kill -l, 可以列出系統(tǒng)支持的所有信號(hào):

 

C代碼  收藏代碼
  1. ~> kill -l  
  2.  1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP  
  3.  6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1  
  4. 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM  
  5. 16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP  
  6. 21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ  
  7. 26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR  
  8. 31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  
  9. 38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8  
  10. 43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13  
  11. 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12  
  12. 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  
  13. 58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2  
  14. 63) SIGRTMAX-1  64) SIGRTMAX      

非可靠信號(hào)一般都有確定的用途及含義,  可靠信號(hào)則可以讓用戶自定義使用

 

二 信號(hào)的安裝

 

早期的Linux使用系統(tǒng)調(diào)用 signal 來安裝信號(hào)


#include <signal.h>

void (*signal(int signum, void (*handler))(int)))(int); 

該函數(shù)有兩個(gè)參數(shù), signum指定要安裝的信號(hào), handler指定信號(hào)的處理函數(shù).

該函數(shù)的返回值是一個(gè)函數(shù)指針, 指向上次安裝的handler


經(jīng)典安裝方式:

if (signal(SIGINT, SIG_IGN) != SIG_IGN) {

    signal(SIGINT, sig_handler);

}

先獲得上次的handler, 如果不是忽略信號(hào), 就安裝此信號(hào)的handler


由于信號(hào)被交付后, 系統(tǒng)自動(dòng)的重置handler為默認(rèn)動(dòng)作, 為了使信號(hào)在handler

處理期間, 仍能對(duì)后繼信號(hào)做出反應(yīng), 往往在handler的第一條語句再次調(diào)用 signal


sig_handler(ing signum)

{

    /* 重新安裝信號(hào) */

    signal(signum, sig_handler);

    ......

}

我們知道在程序的任意執(zhí)行點(diǎn)上, 信號(hào)隨時(shí)可能發(fā)生, 如果信號(hào)在sig_handler重新安裝

信號(hào)之前產(chǎn)生, 這次信號(hào)就會(huì)執(zhí)行默認(rèn)動(dòng)作, 而不是sig_handler. 這種問題是不可預(yù)料的.


使用庫函數(shù) sigaction  來安裝信號(hào)

為了克服非可靠信號(hào)并同一SVR4和BSD之間的差異, 產(chǎn)生了 POSIX 信號(hào)安裝方式, 使用

sigaction安裝信號(hào)的動(dòng)作后, 該動(dòng)作就一直保持, 直到另一次調(diào)用 sigaction建立另一個(gè)

動(dòng)作為止. 這就克服了古老的 signal 調(diào)用存在的問題


#include <signal.h> 
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));


經(jīng)典安裝方式:


struct sigaction action, old_action;



/* 設(shè)置SIGINT */

action.sa_handler = sig_handler;

sigemptyset(&action.sa_mask);

sigaddset(&action.sa_mask, SIGTERM);

action.sa_flags = 0;


/* 獲取上次的handler, 如果不是忽略動(dòng)作, 則安裝信號(hào) */

sigaction(SIGINT, NULL, &old_action);

if (old_action.sa_handler != SIG_IGN) {

    sigaction(SIGINT, &action, NULL);

}


基于 sigaction 實(shí)現(xiàn)的庫函數(shù): signal

sigaction 自然強(qiáng)大, 但安裝信號(hào)很繁瑣, 目前l(fā)inux中的signal()是通過sigation()函數(shù)

實(shí)現(xiàn)的,因此,即使通過signal()安裝的信號(hào),在信號(hào)處理函數(shù)的結(jié)尾也不必

再調(diào)用一次信號(hào)安裝函數(shù)。

 

三 如何屏蔽信號(hào)

 

所謂屏蔽, 并不是禁止遞送信號(hào), 而是暫時(shí)阻塞信號(hào)的遞送, 

解除屏蔽后, 信號(hào)將被遞送, 不會(huì)丟失. 相關(guān)API為


int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signum);

int sigdelset(sigset_t *set, int signum);

int sigismember(const sigset_t *set, int signum);

int sigsuspend(const sigset_t *mask);

int sigpending(sigset_t *set);

-----------------------------------------------------------------

int  sigprocmask(int  how,  const  sigset_t *set, sigset_t *oldset));

sigprocmask()函數(shù)能夠根據(jù)參數(shù)how來實(shí)現(xiàn)對(duì)信號(hào)集的操作,操作主要有三種:

* SIG_BLOCK 在進(jìn)程當(dāng)前阻塞信號(hào)集中添加set指向信號(hào)集中的信號(hào)

* SIG_UNBLOCK 如果進(jìn)程阻塞信號(hào)集中包含set指向信號(hào)集中的信號(hào),則解除

   對(duì)該信號(hào)的阻塞

* SIG_SETMASK 更新進(jìn)程阻塞信號(hào)集為set指向的信號(hào)集


屏蔽整個(gè)進(jìn)程的信號(hào):

 

C代碼  收藏代碼
#include <signal.h>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<error.h>
#include 
<string.h>

void sig_handler(int signum)
{
    printf(
"catch SIGINT\n");
}

int main(int argc, char **argv)
{
    sigset_t block;
    
struct sigaction action, old_action;

    
/* 安裝信號(hào) */
    action.sa_handler 
= sig_handler;
    sigemptyset(
&action.sa_mask);
    action.sa_flags 
= 0;

    sigaction(SIGINT, NULL, 
&old_action);
    
if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGINT, 
&action, NULL);
    }

    
/* 屏蔽信號(hào) */
    sigemptyset(
&block);
    sigaddset(
&block, SIGINT);

    printf(
"block SIGINT\n");
    sigprocmask(SIG_BLOCK, 
&block, NULL);

    printf(
"--> send SIGINT -->\n");
    kill(getpid(), SIGINT);
    printf(
"--> send SIGINT -->\n");
    kill(getpid(), SIGINT);
    sleep(
1);

    
/* 解除信號(hào)后, 之前觸發(fā)的信號(hào)將被遞送,
     * 但SIGINT是非可靠信號(hào), 只會(huì)遞送一次
     
*/
    printf(
"unblock SIGINT\n");
    sigprocmask(SIG_UNBLOCK, 
&block, NULL);

    sleep(
2);

    
return 0;
}

 運(yùn)行結(jié)果:

 

C代碼  收藏代碼
work> ./a.out   
block SIGINT  
--> send SIGINT -->  
--> send SIGINT -->  
unblock SIGINT  
catch SIGINT

這里發(fā)送了兩次SIGINT信號(hào) 可以看到, 屏蔽掉SIGINT后,

信號(hào)無法遞送, 解除屏蔽后, 才遞送信號(hào), 但只被遞送一次,

因?yàn)镾IGINT是非可靠信號(hào), 不支持排隊(duì).


只在信號(hào)處理期間, 屏蔽其它信號(hào)

在信號(hào)的handler執(zhí)行期間, 系統(tǒng)將自動(dòng)屏蔽此信號(hào), 但如果

還想屏蔽其它信號(hào)怎么辦?  可以利用 struct sigaction 結(jié)構(gòu)體

的 sa_mask 屬性.

 

C代碼  收藏代碼
#include <signal.h>  
#include 
<stdio.h>  
#include 
<stdlib.h>  
#include 
<error.h>  
#include 
<string.h>  
  
void sig_handler(int signum)  
{  
    printf(
"in handle, SIGTERM is blocked\n");  
    
/* 在此handler內(nèi)將屏蔽掉SIGTERM, 直到此handler返回 */  
    printf(
"--> send SIGTERM -->\n");  
    kill(getpid(), SIGTERM);  
    sleep(
5);  
    printf(
"handle done\n");  
}  
  
void handle_term(int signum)  
{  
    printf(
"catch sigterm and exit..\n");  
    exit(
0);  
}  
  
int main(int argc, char **argv)  
{  
    
struct sigaction action, old_action;  
  
    
/* 設(shè)置SIGINT */  
    action.sa_handler 
= sig_handler;  
    sigemptyset(
&action.sa_mask);  
    
/* 安裝handler的時(shí)候, 設(shè)置在handler 
     * 執(zhí)行期間, 屏蔽掉SIGTERM信號(hào) 
*/  
    sigaddset(
&action.sa_mask, SIGTERM);  
    action.sa_flags 
= 0;  
  
    sigaction(SIGINT, NULL, 
&old_action);  
    
if (old_action.sa_handler != SIG_IGN) {  
        sigaction(SIGINT, 
&action, NULL);  
    }  
  
    
/* 設(shè)置SIGTERM */  
    action.sa_handler 
= handle_term;  
    sigemptyset(
&action.sa_mask);  
    action.sa_flags 
= 0;  
  
    sigaction(SIGTERM, NULL, 
&old_action);  
    
if (old_action.sa_handler != SIG_IGN) {  
        sigaction(SIGTERM, 
&action, NULL);  
    }  
  
    printf(
"--> send SIGINT -->\n");  
    kill(getpid(), SIGINT);  
  
    
while (1) {  
        sleep(
1);  
    }  
  
    
return 0;  
}

 

運(yùn)行結(jié)果:

 

C代碼  收藏代碼
work> ./a.out
--> send SIGINT -->
in handle, SIGTERM is blocked
--> send SIGTERM -->
handle done
catch sigterm and exit..

 收到SIGINT后, 進(jìn)入sig_handler,此時(shí)發(fā)送SIGTERM信號(hào)將被屏蔽,

 等sig_handler返回后, 才收到SIGTERM信號(hào), 然后退出程序

 

 

四 如何獲取未決信號(hào)

所謂未決信號(hào), 是指被阻塞的信號(hào), 等待被遞送的信號(hào). 


int sigsuspend(const sigset_t *mask));

sigpending(sigset_t *set))獲得當(dāng)前已遞送到進(jìn)程,

卻被阻塞的所有信號(hào),在set指向的信號(hào)集中返回結(jié)果。

 

C代碼  收藏代碼
#include <signal.h>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<error.h>
#include 
<string.h>

/* 版本1, 可靠信號(hào)將被遞送多次 */
//#define MYSIGNAL SIGRTMIN+5
/*
 版本2, 不可靠信號(hào)只被遞送一次 */
#define MYSIGNAL SIGTERM

void sig_handler(int signum)
{
    psignal(signum, 
"catch a signal");
}

int main(int argc, char **argv)
{
    sigset_t block, pending;
    
int sig, flag;

    
/* 設(shè)置信號(hào)的handler */
    signal(MYSIGNAL, sig_handler);

    
/* 屏蔽此信號(hào) */
    sigemptyset(
&block);
    sigaddset(
&block, MYSIGNAL);
    printf(
"block signal\n");
    sigprocmask(SIG_BLOCK, 
&block, NULL);

    
/* 發(fā)兩次信號(hào), 看信號(hào)將會(huì)被觸發(fā)多少次 */
    printf(
"---> send a signal --->\n");
    kill(getpid(), MYSIGNAL);
    printf(
"---> send a signal --->\n");
    kill(getpid(), MYSIGNAL);

    
/* 檢查當(dāng)前的未決信號(hào) */
    flag 
= 0;
    sigpending(
&pending);
    
for (sig = 1; sig < NSIG; sig++) {
        
if (sigismember(&pending, sig)) {
            flag 
= 1;
            psignal(sig, 
"this signal is pending");
        } 
    }
    
if (flag == 0) {
        printf(
"no pending signal\n");
    }

    
/* 解除此信號(hào)的屏蔽, 未決信號(hào)將被遞送 */
    printf(
"unblock signal\n");
    sigprocmask(SIG_UNBLOCK, 
&block, NULL);

    
/* 再次檢查未決信號(hào) */
    flag 
= 0;
    sigpending(
&pending);
    
for (sig = 1; sig < NSIG; sig++) {
        
if (sigismember(&pending, sig)) {
            flag 
= 1;
            psignal(sig, 
"a pending signal");
        } 
    }
    
if (flag == 0) {
        printf(
"no pending signal\n");
    }

    
return 0;
}

  這個(gè)程序有兩個(gè)版本:

可靠信號(hào)版本, 運(yùn)行結(jié)果:

C代碼  收藏代碼
work> ./a.out   
block signal  
---> send a signal --->  
---> send a signal --->  
this signal is pending: Unknown signal 39  
unblock signal  
catch a signal: Unknown signal 39  
catch a signal: Unknown signal 39  
no pending signal

發(fā)送兩次可靠信號(hào), 最終收到兩次信號(hào)


非可靠信號(hào)版本, 運(yùn)行結(jié)果:

 

C代碼  收藏代碼
work> ./a.out   
block signal  
---> send a signal --->  
---> send a signal --->  
this signal is pending: Terminated  
unblock signal  
catch a signal: Terminated  
no pending signal

  發(fā)送兩次非可靠信號(hào), 最終只收到一次

 

五 被中斷了的系統(tǒng)調(diào)用

一些IO系統(tǒng)調(diào)用執(zhí)行時(shí), 如 read 等待輸入期間, 如果收到一個(gè)信號(hào),

系統(tǒng)將中斷read, 轉(zhuǎn)而執(zhí)行信號(hào)處理函數(shù). 當(dāng)信號(hào)處理返回后, 系統(tǒng)

遇到了一個(gè)問題: 是重新開始這個(gè)系統(tǒng)調(diào)用, 還是讓系統(tǒng)調(diào)用失敗?


早期UNIX系統(tǒng)的做法是, 中斷系統(tǒng)調(diào)用, 并讓系統(tǒng)調(diào)用失敗, 比如read

返回 -1, 同時(shí)設(shè)置 errno 為 EINTR


中斷了的系統(tǒng)調(diào)用是沒有完成的調(diào)用, 它的失敗是臨時(shí)性的, 如果再次調(diào)用

則可能成功, 這并不是真正的失敗, 所以要對(duì)這種情況進(jìn)行處理, 典型的方式為:


while (1) {

    n = read(fd, buf, BUFSIZ);

    if (n == -1 && errno != EINTR) {

        printf("read error\n");

        break;

    }

    if (n == 0) {

        printf("read done\n");

        break;

    }

}


這樣做邏輯比較繁瑣, 事實(shí)上, 我們可以從信號(hào)的角度

來解決這個(gè)問題,  安裝信號(hào)的時(shí)候, 設(shè)置 SA_RESTART

屬性, 那么當(dāng)信號(hào)處理函數(shù)返回后, 被該信號(hào)中斷的系統(tǒng)

調(diào)用將自動(dòng)恢復(fù). 

 

C代碼  收藏代碼

    #include <signal.h>  
    #include 
<stdio.h>  
    #include 
<stdlib.h>  
    #include 
<error.h>  
    #include 
<string.h>  
      
    
void sig_handler(int signum)  
    {  
        printf(
"in handler\n");  
        sleep(
1);  
        printf(
"handler return\n");  
    }  
      
    
int main(int argc, char **argv)  
    {  
        
char buf[100];  
        
int ret;  
        
struct sigaction action, old_action;  
      
        action.sa_handler 
= sig_handler;  
        sigemptyset(
&action.sa_mask);  
        action.sa_flags 
= 0;  
        
/* 版本1:不設(shè)置SA_RESTART屬性 
         * 版本2:設(shè)置SA_RESTART屬性 
*/  
        
//action.sa_flags |= SA_RESTART;  
      
        sigaction(SIGINT, NULL, 
&old_action);  
        
if (old_action.sa_handler != SIG_IGN) {  
            sigaction(SIGINT, 
&action, NULL);  
        }  
      
        bzero(buf, 
100);  
      
        ret 
= read(0, buf, 100);  
        
if (ret == -1) {  
            perror(
"read");  
        }  
      
        printf(
"read %d bytes:\n", ret);  
        printf(
"%s\n", buf);  
      
        
return 0;  
    } 

 

版本1, 不設(shè)置 SA_RESTART 屬性 :

 

C代碼  收藏代碼
work> gcc signal.c   
work
> ./a.out   
^Cin handler  
handler 
return  
read: Interrupted system call  
read 
-1 bytes:

在 read 等待數(shù)據(jù)期間, 按下ctrl + c, 觸發(fā) SIGINT 信號(hào), 

handler 返回后, read 被中斷, 返回 -1


版本2, 設(shè)置 SA_RESTART 屬性:

 

C代碼  收藏代碼
work> gcc signal.c   
work
> ./a.out   
^Cin handler  
handler 
return  
hello, world  
read 
13 bytes:  
hello, world

 handler 返回后, read 系統(tǒng)調(diào)用被恢復(fù)執(zhí)行, 繼續(xù)等待數(shù)據(jù).

 

 

六 非局部控制轉(zhuǎn)移


int setjmp(jmp_buf env);

int sigsetjmp(sigjmp_buf env, int savesigs);

void longjmp(jmp_buf env, int val);

void siglongjmp(sigjmp_buf env, int val);

--------------------------------------------------------

setjmp()會(huì)保存目前堆棧環(huán)境,然后將目前的地址作一個(gè)記號(hào),

而在程序其他地方調(diào)用 longjmp 時(shí)便會(huì)直接跳到這個(gè)記號(hào)位置,

然后還原堆棧,繼續(xù)程序好執(zhí)行。 


setjmp調(diào)用有點(diǎn)fork的味道, setjmp()return 0 if returning directly, 

and non-zero when returning from longjmp using  the saved context.


if (setjmp(jmpbuf)) {

   printf("return from jmp\n");

} else {

   printf("return directly\n");

}


setjmp 和 sigsetjmp 的唯一區(qū)別是: setjmp 不一定會(huì)恢復(fù)信號(hào)集合,

而sigsetjmp可以保證恢復(fù)信號(hào)集合

 

C代碼  收藏代碼

#include <signal.h>
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<errno.h>
#include 
<string.h>
#include 
<setjmp.h>

void sig_alrm(int signum);
void sig_usr1(int signum);
void print_mask(const char *str);

static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
static int sigalrm_appear;

int main(int argc, char **argv)
{
    
struct sigaction action, old_action;

    
/* 設(shè)置SIGUSR1 */
    action.sa_handler 
= sig_usr1;
    sigemptyset(
&action.sa_mask);
    action.sa_flags 
= 0;

    sigaction(SIGUSR1, NULL, 
&old_action);
    
if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGUSR1, 
&action, NULL);
    }

    
/* 設(shè)置SIGALRM */
    action.sa_handler 
= sig_alrm;
    sigemptyset(
&action.sa_mask);
    action.sa_flags 
= 0;

    sigaction(SIGALRM, NULL, 
&old_action);
    
if (old_action.sa_handler != SIG_IGN) {
        sigaction(SIGALRM, 
&action, NULL);
    }

    print_mask(
"starting main:");

    
if (sigsetjmp(jmpbuf, 1!= 0) {
        print_mask(
"exiting main:");
    } 
else {
        printf(
"sigsetjmp return directly\n");
        canjmp 
= 1;
        
while (1) {
            sleep(
1);
        }
    }

    
return 0;
}

void sig_usr1(int signum)
{
    time_t starttime;
    
if (canjmp == 0) {
        printf(
"please set jmp first\n");
        
return;
    }

    print_mask(
"in sig_usr1:");

    alarm(
1);
    
while (!sigalrm_appear);
    canjmp 
= 0;
    siglongjmp(jmpbuf, 
1);
}

void sig_alrm(int signum)
{
    print_mask(
"in sig_alrm:");
    sigalrm_appear 
= 1;

    
return;
}

void print_mask(const char *str) 
{
    sigset_t sigset;
    
int i, errno_save, flag = 0;

    errno_save 
= errno;

    
if (sigprocmask(0, NULL, &sigset) < 0) {
        printf(
"sigprocmask error\n");
        exit(
0);
    }

    printf(
"%s\n", str);
    fflush(stdout);

    
for (i = 1; i < NSIG; i++) {
        
if (sigismember(&sigset, i)) {
            flag 
= 1;
            psignal(i, 
"a blocked signal");
        }
    }

    
if (!flag) {
        printf(
"no blocked signal\n");
    }

    printf(
"\n");
    errno 
= errno_save;
}

 

運(yùn)行結(jié)果: 

 

C代碼  收藏代碼

work> ./a.out &  
[
428483  
starting main:  
no blocked signal  
  
sigsetjmp 
return directly  
  
kill 
-USR1 28483  
  
in sig_usr1:  
a blocked signal: User defined signal 
1  
  
in sig_alrm:  
a blocked signal: User defined signal 
1  
a blocked signal: Alarm clock  
  
exiting main:  
no blocked signal

 

 

七 信號(hào)的生命周期

 

從信號(hào)發(fā)送到信號(hào)處理函數(shù)的執(zhí)行完畢

對(duì)于一個(gè)完整的信號(hào)生命周期(從信號(hào)發(fā)送到相應(yīng)的處理函數(shù)執(zhí)行完畢)來說,

可以分為三個(gè)重要的階段,這三個(gè)階段由四個(gè)重要事件來刻畫:

信號(hào)誕生;信號(hào)在進(jìn)程中注冊(cè)完畢;信號(hào)在進(jìn)程中的注銷完畢;信號(hào)處理函數(shù)執(zhí)行完畢。


下面闡述四個(gè)事件的實(shí)際意義:

信號(hào)"誕生"。信號(hào)的誕生指的是觸發(fā)信號(hào)的事件發(fā)生

(如檢測(cè)到硬件異常、定時(shí)器超時(shí)以及調(diào)用信號(hào)發(fā)送函數(shù)

kill()或sigqueue()等)。信號(hào)在目標(biāo)進(jìn)程中"注冊(cè)";

進(jìn)程的task_struct結(jié)構(gòu)中有關(guān)于本進(jìn)程中未決信號(hào)的數(shù)據(jù)成員:

struct sigpending pending:

struct sigpending{

struct sigqueue *head, **tail;

sigset_t signal;

};


第三個(gè)成員是進(jìn)程中所有未決信號(hào)集,第一、第二個(gè)成員分別指向一個(gè)

sigqueue類型的結(jié)構(gòu)鏈(稱之為"未決信號(hào)鏈表")的首尾,鏈表中

的每個(gè)sigqueue結(jié)構(gòu)刻畫一個(gè)特定信號(hào)所攜帶的信息,并指向下一個(gè)

sigqueue結(jié)構(gòu):

struct sigqueue{

struct sigqueue *next;

siginfo_t info;

}


信號(hào)的注冊(cè)

信號(hào)在進(jìn)程中注冊(cè)指的就是信號(hào)值加入到進(jìn)程的未決信號(hào)集中

(sigpending結(jié)構(gòu)的第二個(gè)成員sigset_t signal),

并且加入未決信號(hào)鏈表的末尾。 只要信號(hào)在進(jìn)程的未決信號(hào)集中,

表明進(jìn)程已經(jīng)知道這些信號(hào)的存在,但還沒來得及處理,或者該信號(hào)被進(jìn)程阻塞。

當(dāng)一個(gè)實(shí)時(shí)信號(hào)發(fā)送給一個(gè)進(jìn)程時(shí),不管該信號(hào)是否已經(jīng)在進(jìn)程中注冊(cè),

都會(huì)被再注冊(cè)一次,因此,信號(hào)不會(huì)丟失,因此,實(shí)時(shí)信號(hào)又叫做"可靠信號(hào)"。

這意味著同一個(gè)實(shí)時(shí)信號(hào)可以在同一個(gè)進(jìn)程的未決信號(hào)鏈表中添加多次. 

當(dāng)一個(gè)非實(shí)時(shí)信號(hào)發(fā)送給一個(gè)進(jìn)程時(shí),如果該信號(hào)已經(jīng)在進(jìn)程中注冊(cè),

則該信號(hào)將被丟棄,造成信號(hào)丟失。因此,非實(shí)時(shí)信號(hào)又叫做"不可靠信號(hào)"。

這意味著同一個(gè)非實(shí)時(shí)信號(hào)在進(jìn)程的未決信號(hào)鏈表中,至多占有一個(gè)sigqueue結(jié)構(gòu).

一個(gè)非實(shí)時(shí)信號(hào)誕生后,

(1)、如果發(fā)現(xiàn)相同的信號(hào)已經(jīng)在目標(biāo)結(jié)構(gòu)中注冊(cè),則不再注冊(cè),對(duì)于進(jìn)程來說,

相當(dāng)于不知道本次信號(hào)發(fā)生,信號(hào)丟失.

(2)、如果進(jìn)程的未決信號(hào)中沒有相同信號(hào),則在進(jìn)程中注冊(cè)自己。


信號(hào)的注銷。

在進(jìn)程執(zhí)行過程中,會(huì)檢測(cè)是否有信號(hào)等待處理

(每次從系統(tǒng)空間返回到用戶空間時(shí)都做這樣的檢查)。如果存在未決

信號(hào)等待處理且該信號(hào)沒有被進(jìn)程阻塞,則在運(yùn)行相應(yīng)的信號(hào)處理函數(shù)前,

進(jìn)程會(huì)把信號(hào)在未決信號(hào)鏈中占有的結(jié)構(gòu)卸掉。是否將信號(hào)從進(jìn)程未決信號(hào)集

中刪除對(duì)于實(shí)時(shí)與非實(shí)時(shí)信號(hào)是不同的。對(duì)于非實(shí)時(shí)信號(hào)來說,由于在未決信

號(hào)信息鏈中最多只占用一個(gè)sigqueue結(jié)構(gòu),因此該結(jié)構(gòu)被釋放后,應(yīng)該把信

號(hào)在進(jìn)程未決信號(hào)集中刪除(信號(hào)注銷完畢);而對(duì)于實(shí)時(shí)信號(hào)來說,可能在

未決信號(hào)信息鏈中占用多個(gè)sigqueue結(jié)構(gòu),因此應(yīng)該針對(duì)占用sigqueue結(jié)構(gòu)

的數(shù)目區(qū)別對(duì)待:如果只占用一個(gè)sigqueue結(jié)構(gòu)(進(jìn)程只收到該信號(hào)一次),

則應(yīng)該把信號(hào)在進(jìn)程的未決信號(hào)集中刪除(信號(hào)注銷完畢)。否則,不應(yīng)該在進(jìn)程

的未決信號(hào)集中刪除該信號(hào)(信號(hào)注銷完畢)。 

進(jìn)程在執(zhí)行信號(hào)相應(yīng)處理函數(shù)之前,首先要把信號(hào)在進(jìn)程中注銷。


信號(hào)生命終止。

進(jìn)程注銷信號(hào)后,立即執(zhí)行相應(yīng)的信號(hào)處理函數(shù),執(zhí)行完畢后,

信號(hào)的本次發(fā)送對(duì)進(jìn)程的影響徹底結(jié)束。

 

八 關(guān)于可重入函數(shù)

 

在信號(hào)處理函數(shù)中應(yīng)使用可重入函數(shù)。

信號(hào)處理程序中應(yīng)當(dāng)使用可重入函數(shù)

(注:所謂可重入函數(shù)是指一個(gè)可以被多個(gè)任務(wù)調(diào)用的過程,

任務(wù)在調(diào)用時(shí)不必?fù)?dān)心數(shù)據(jù)是否會(huì)出錯(cuò))。因?yàn)檫M(jìn)程在收到信號(hào)

后,就將跳轉(zhuǎn)到信號(hào)處理函數(shù)去接著執(zhí)行。如果信號(hào)處理函數(shù)中

使用了不可重入函數(shù),那么信號(hào)處理函數(shù)可能會(huì)修改原來進(jìn)程中

不應(yīng)該被修改的數(shù)據(jù),這樣進(jìn)程從信號(hào)處理函數(shù)中返回接著執(zhí)行時(shí),

可能會(huì)出現(xiàn)不可預(yù)料的后果。不可再入函數(shù)在信號(hào)處理函數(shù)中被視為

不安全函數(shù)。滿足下列條件的函數(shù)多數(shù)是不可再入的:

(1)使用靜態(tài)的數(shù)據(jù)結(jié)構(gòu),如getlogin(),gmtime(),getgrgid(),

    getgrnam(),getpwuid()以及getpwnam()等等;

(2)函數(shù)實(shí)現(xiàn)時(shí),調(diào)用了malloc()或者free()函數(shù);

(3)實(shí)現(xiàn)時(shí)使用了標(biāo)準(zhǔn)I/O函數(shù)的。The Open Group視下列函數(shù)為可再入的:

    _exit()、access()、alarm()、cfgetispeed()、cfgetospeed()、

    cfsetispeed()、cfsetospeed()、chdir()、chmod()、chown() 、

    close()、creat()、dup()、dup2()、execle()、execve()、

    fcntl()、fork()、fpathconf()、fstat()、fsync()、getegid()、

    geteuid()、getgid()、getgroups()、getpgrp()、getpid()、

    getppid()、getuid()、kill()、link()、lseek()、mkdir()、

    mkfifo()、 open()、pathconf()、pause()、pipe()、raise()、

    read()、rename()、rmdir()、setgid()、setpgid()、setsid()、

    setuid()、 sigaction()、sigaddset()、sigdelset()、sigemptyset()、

    sigfillset()、sigismember()、signal()、sigpending()、     

    sigprocmask()、sigsuspend()、sleep()、stat()、sysconf()、      

    tcdrain()、tcflow()、tcflush()、tcgetattr()、tcgetpgrp()、

    tcsendbreak()、tcsetattr()、tcsetpgrp()、time()、times()、

    umask()、uname()、unlink()、utime()、wait()、waitpid()、

    write()。


即使信號(hào)處理函數(shù)使用的都是"安全函數(shù)",同樣要注意進(jìn)入處理函數(shù)時(shí),

首先要保存errno的值,結(jié)束時(shí),再恢復(fù)原值。因?yàn)椋盘?hào)處理過程中,

errno值隨時(shí)可能被改變。另外,longjmp()以及siglongjmp()沒有被列為可重入函數(shù),

因?yàn)椴荒鼙WC緊接著兩個(gè)函數(shù)的其它調(diào)用是安全的。


轉(zhuǎn)自:http://kenby.iteye.com/blog/1173862
posted on 2013-01-13 12:31 小果子 閱讀(610) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 學(xué)習(xí)筆記Linux
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            日韩一级免费观看| 欧美一区二区在线播放| 亚洲在线免费| 日韩午夜免费| av成人毛片| 亚洲欧美激情四射在线日 | 欧美国产另类| 欧美人体xx| 国产精品男女猛烈高潮激情| 国产精品一区二区久久久| 国产亚洲成年网址在线观看| 在线播放日韩专区| 99精品国产在热久久下载| 亚洲香蕉网站| 久久久女女女女999久久| 免费看亚洲片| 99国产精品| 久久精品青青大伊人av| 欧美久久成人| 国产日韩三区| 亚洲每日在线| 久久av最新网址| 欧美黑人在线观看| 一区二区三区福利| 开心色5月久久精品| 欧美视频一区二区三区四区| 国产午夜精品在线观看| 亚洲精品一区二区三区四区高清 | 这里是久久伊人| 久久精品欧美| 亚洲人体影院| 亚洲免费中文字幕| 欧美国产日韩一区二区三区| 国产欧美欧美| 亚洲美洲欧洲综合国产一区| 欧美在线1区| 亚洲精品一级| 久久一区二区三区av| 国产精品三上| 亚洲视频一区二区| 欧美韩日一区二区三区| 久久九九热re6这里有精品| 国产精品久久久久一区二区| 亚洲久色影视| 一区二区91| 欧美大片一区二区三区| 午夜精品久久久久久久 | 欧美成人精品在线播放| 国产精品户外野外| 日韩一区二区精品视频| 久久综合色播五月| 午夜精品剧场| 国产精品蜜臀在线观看| 洋洋av久久久久久久一区| 久久综合999| 新狼窝色av性久久久久久| 国产精品国产a级| 亚洲视频你懂的| 日韩网站免费观看| 欧美精品色综合| 亚洲精品日韩久久| 亚洲欧洲一区二区三区在线观看 | 久久久精品日韩| 国产一区二区三区免费不卡| 欧美在线不卡| 午夜精品99久久免费| 国产欧美欧美| 久久综合色8888| 久久久久9999亚洲精品| 国产视频一区在线观看| 久久精品国产精品亚洲精品| 亚洲欧美成人在线| 国产一区二区黄| 麻豆国产精品777777在线| 久久麻豆一区二区| 亚洲国产影院| 亚洲精品美女久久7777777| 欧美日韩成人一区| 亚洲男人的天堂在线观看| 亚洲欧美国产va在线影院| 韩日精品中文字幕| 欧美激情一区二区三区全黄| 欧美久久电影| 欧美有码在线观看视频| 美女露胸一区二区三区| 一本色道久久综合亚洲精品婷婷| 日韩香蕉视频| 国产综合亚洲精品一区二| 欧美国产精品专区| 国产精品区一区二区三| 欧美成人一区二区| 欧美性久久久| 欧美凹凸一区二区三区视频| 欧美日韩一区不卡| 久久久久88色偷偷免费| 欧美日韩国产经典色站一区二区三区| 午夜精品国产更新| 久久视频一区二区| 亚洲欧美视频一区| 欧美国产日本| 久久国产精品99久久久久久老狼 | 欧美在线一区二区| 一本色道久久综合狠狠躁篇的优点 | 久久嫩草精品久久久精品| 欧美激情成人在线| 欧美激情久久久久| 亚洲精品久久久蜜桃| 亚洲一区二区三区在线播放| 国产精品自拍三区| 免费日本视频一区| 欧美精品一级| 国内精品久久久久影院薰衣草| 日韩系列欧美系列| 韩国成人福利片在线播放| 亚洲高清在线精品| 国产精品av免费在线观看| 久久精品理论片| 久久er精品视频| 99精品99| 欧美亚洲日本一区| 亚洲精品一区二区三区99| 先锋资源久久| 中文av一区二区| 久久精品国产免费观看| 亚洲一二三区在线观看| 欧美一区二区三区免费看| 一区二区三区精品在线| 久久九九精品99国产精品| 亚洲女人天堂av| 欧美韩日一区| 欧美成人精品高清在线播放| 韩国三级电影久久久久久| 亚洲午夜免费福利视频| 日韩手机在线导航| 久久夜色精品国产亚洲aⅴ| 午夜在线视频一区二区区别| 欧美激情女人20p| 亚洲毛片在线观看.| 亚洲激情在线| 久久激情网站| 久久九九精品| 国产精品久在线观看| 久久久久国产精品厨房| 激情综合中文娱乐网| 亚洲淫性视频| 亚洲欧美日韩综合国产aⅴ| 欧美日韩在线不卡一区| 99riav1国产精品视频| 亚洲精选在线观看| 欧美成人中文| 亚洲欧洲一区二区三区久久| 亚洲九九九在线观看| 久久午夜精品| 久久婷婷人人澡人人喊人人爽| 国产日本欧美一区二区三区| 午夜视频在线观看一区二区| 亚洲欧美国产高清| 亚洲视频 欧洲视频| 久久精品国产清高在天天线| 国产精品yjizz| 在线亚洲激情| 欧美亚洲在线播放| 国产精品视频内| 久久综合九色综合欧美就去吻| 老鸭窝91久久精品色噜噜导演| 国内不卡一区二区三区| 久久久久久久一区二区| 你懂的视频欧美| 正在播放日韩| 欧美日韩一区二区在线| 免费人成网站在线观看欧美高清| 国产一区视频网站| 久久人人精品| 亚洲国产老妈| 一区二区三区精品视频在线观看 | 久久精品二区三区| 永久免费精品影视网站| 欧美大片免费观看| 亚洲视频二区| 蜜桃av噜噜一区二区三区| 亚洲人成高清| 久久av资源网站| 在线观看亚洲视频| 欧美激情精品久久久久久黑人 | 久久看片网站| 亚洲裸体视频| 久久久久久久一区二区| 亚洲日本电影| 国产欧美 在线欧美| 欧美日韩在线播放三区| 久久久久久久久久久久久9999| 91久久午夜| 久久成人人人人精品欧| 亚洲欧洲在线一区| 国产主播一区二区三区| 欧美精品一区二区精品网| 欧美一区二区视频观看视频| 亚洲美女黄网| 欧美激情视频免费观看| 久久精品女人|