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

xiaoguozi's Blog
Pay it forword - 我并不覺的自豪,我所嘗試的事情都失敗了······習(xí)慣原本生活的人不容易改變,就算現(xiàn)狀很糟,他們也很難改變,在過程中,他們還是放棄了······他們一放棄,大家就都是輸家······讓愛傳出去,很困難,也無法預(yù)料,人們需要更細心的觀察別人,要隨時注意才能保護別人,因為他們未必知道自己要什么·····

一 信號的種類

可靠信號與不可靠信號, 實時信號與非實時信號

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

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

SIGRTMIN的都是非可靠信號.

非可靠信號就是非實時信號, 后來, Linux改進了信號機制, 增加了32種新的信號, 這些信

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

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

 

關(guān)于可靠信號, 還可以參考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)支持的所有信號:

 

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      

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

 

二 信號的安裝

 

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


#include <signal.h>

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

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

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


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

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

    signal(SIGINT, sig_handler);

}

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


由于信號被交付后, 系統(tǒng)自動的重置handler為默認動作, 為了使信號在handler

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


sig_handler(ing signum)

{

    /* 重新安裝信號 */

    signal(signum, sig_handler);

    ......

}

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

信號之前產(chǎn)生, 這次信號就會執(zhí)行默認動作, 而不是sig_handler. 這種問題是不可預(yù)料的.


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

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

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

動作為止. 這就克服了古老的 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, 如果不是忽略動作, 則安裝信號 */

sigaction(SIGINT, NULL, &old_action);

if (old_action.sa_handler != SIG_IGN) {

    sigaction(SIGINT, &action, NULL);

}


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

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

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

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

 

三 如何屏蔽信號

 

所謂屏蔽, 并不是禁止遞送信號, 而是暫時阻塞信號的遞送, 

解除屏蔽后, 信號將被遞送, 不會丟失. 相關(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來實現(xiàn)對信號集的操作,操作主要有三種:

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

* SIG_UNBLOCK 如果進程阻塞信號集中包含set指向信號集中的信號,則解除

   對該信號的阻塞

* SIG_SETMASK 更新進程阻塞信號集為set指向的信號集


屏蔽整個進程的信號:

 

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;

    
/* 安裝信號 */
    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);
    }

    
/* 屏蔽信號 */
    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);

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

    sleep(
2);

    
return 0;
}

 運行結(jié)果:

 

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

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

信號無法遞送, 解除屏蔽后, 才遞送信號, 但只被遞送一次,

因為SIGINT是非可靠信號, 不支持排隊.


只在信號處理期間, 屏蔽其它信號

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

還想屏蔽其它信號怎么辦?  可以利用 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è)置在handler 
     * 執(zhí)行期間, 屏蔽掉SIGTERM信號 
*/  
    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;  
}

 

運行結(jié)果:

 

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

 收到SIGINT后, 進入sig_handler,此時發(fā)送SIGTERM信號將被屏蔽,

 等sig_handler返回后, 才收到SIGTERM信號, 然后退出程序

 

 

四 如何獲取未決信號

所謂未決信號, 是指被阻塞的信號, 等待被遞送的信號. 


int sigsuspend(const sigset_t *mask));

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

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

 

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

/* 版本1, 可靠信號將被遞送多次 */
//#define MYSIGNAL SIGRTMIN+5
/*
 版本2, 不可靠信號只被遞送一次 */
#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è)置信號的handler */
    signal(MYSIGNAL, sig_handler);

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

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

    
/* 檢查當(dāng)前的未決信號 */
    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");
    }

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

    
/* 再次檢查未決信號 */
    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;
}

  這個程序有兩個版本:

可靠信號版本, 運行結(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ā)送兩次可靠信號, 最終收到兩次信號


非可靠信號版本, 運行結(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ā)送兩次非可靠信號, 最終只收到一次

 

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

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

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

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


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

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


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

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


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è)置 SA_RESTART

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

調(diào)用將自動恢復(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 信號, 

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án)境,然后將目前的地址作一個記號,

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

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


setjmp調(diào)用有點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 不一定會恢復(fù)信號集合,

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

 

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;
}

 

運行結(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

 

 

七 信號的生命周期

 

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

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

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

信號誕生;信號在進程中注冊完畢;信號在進程中的注銷完畢;信號處理函數(shù)執(zhí)行完畢。


下面闡述四個事件的實際意義:

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

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

kill()或sigqueue()等)。信號在目標進程中"注冊";

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

struct sigpending pending:

struct sigpending{

struct sigqueue *head, **tail;

sigset_t signal;

};


第三個成員是進程中所有未決信號集,第一、第二個成員分別指向一個

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

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

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

struct sigqueue{

struct sigqueue *next;

siginfo_t info;

}


信號的注冊

信號在進程中注冊指的就是信號值加入到進程的未決信號集中

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

并且加入未決信號鏈表的末尾。 只要信號在進程的未決信號集中,

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

當(dāng)一個實時信號發(fā)送給一個進程時,不管該信號是否已經(jīng)在進程中注冊,

都會被再注冊一次,因此,信號不會丟失,因此,實時信號又叫做"可靠信號"。

這意味著同一個實時信號可以在同一個進程的未決信號鏈表中添加多次. 

當(dāng)一個非實時信號發(fā)送給一個進程時,如果該信號已經(jīng)在進程中注冊,

則該信號將被丟棄,造成信號丟失。因此,非實時信號又叫做"不可靠信號"。

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

一個非實時信號誕生后,

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

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

(2)、如果進程的未決信號中沒有相同信號,則在進程中注冊自己。


信號的注銷。

在進程執(zhí)行過程中,會檢測是否有信號等待處理

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

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

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

中刪除對于實時與非實時信號是不同的。對于非實時信號來說,由于在未決信

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

號在進程未決信號集中刪除(信號注銷完畢);而對于實時信號來說,可能在

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

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

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

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

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


信號生命終止。

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

信號的本次發(fā)送對進程的影響徹底結(jié)束。

 

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

 

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

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

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

任務(wù)在調(diào)用時不必擔(dān)心數(shù)據(jù)是否會出錯)。因為進程在收到信號

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

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

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

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

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

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

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

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

(3)實現(xià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()。


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

首先要保存errno的值,結(jié)束時,再恢復(fù)原值。因為,信號處理過程中,

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

因為不能保證緊接著兩個函數(shù)的其它調(diào)用是安全的。


轉(zhuǎn)自:http://kenby.iteye.com/blog/1173862
posted on 2013-01-13 12:31 小果子 閱讀(610) 評論(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>
            亚洲女女做受ⅹxx高潮| 女主播福利一区| 麻豆精品一区二区综合av| 午夜在线视频观看日韩17c| 亚洲免费小视频| 午夜精品在线观看| 久久久久九九九九| 欧美大片一区二区| 99亚洲一区二区| 亚洲综合成人婷婷小说| 久久久精品性| 免费影视亚洲| 国产精品久久91| 黄色精品免费| 一区二区三区精品在线| 久久精品99国产精品日本| 欧美sm重口味系列视频在线观看| 亚洲国产婷婷香蕉久久久久久| 久久久久久婷| 欧美激情一区二区三级高清视频| 亚洲视频www| 久久国产免费看| 欧美国产日本高清在线| 国产欧美日韩专区发布| 亚洲国产另类精品专区| 中文欧美字幕免费| 久久久无码精品亚洲日韩按摩| 久久久免费精品| 午夜视频在线观看一区二区三区 | 亚洲天堂激情| 欧美一区二区女人| 欧美精品一区二区在线播放| 中文精品视频一区二区在线观看| 久久国产精品电影| 国产精品二区在线| 亚洲激情在线观看| 久久久成人网| 日韩午夜激情电影| 久久久一本精品99久久精品66| 欧美日韩中文字幕在线| 91久久精品国产| 久久亚洲国产成人| 亚洲欧美日韩系列| 国产精品v欧美精品v日韩| 亚洲人午夜精品免费| 狠狠色2019综合网| 欧美一区二粉嫩精品国产一线天| 亚洲国产精品一区制服丝袜| 亚洲欧美成人一区二区在线电影| 欧美丝袜一区二区| 亚洲日本中文字幕| 久久综合中文色婷婷| 亚洲天堂成人| 欧美三级网址| 亚洲毛片在线看| 蜜月aⅴ免费一区二区三区| 亚洲综合色视频| 欧美极品影院| 亚洲美女尤物影院| 欧美成人午夜激情在线| 久久精品国产99精品国产亚洲性色 | 性欧美在线看片a免费观看| 欧美电影在线免费观看网站| 国产真实乱子伦精品视频| 欧美一区免费视频| 亚洲视频在线免费观看| 欧美精品www| 99伊人成综合| 亚洲欧洲综合另类| 欧美成人高清视频| 一区二区三区色| 一区二区三区 在线观看视| 欧美理论在线播放| 午夜精品久久久久| 久久精品91| 亚洲欧洲日本国产| 亚洲国内欧美| 欧美午夜在线视频| 久久成人免费电影| 亚洲精选中文字幕| 亚洲黄网站黄| 最新国产成人在线观看| 欧美精品久久久久a| 宅男噜噜噜66国产日韩在线观看| 9人人澡人人爽人人精品| 国产精品jizz在线观看美国| 欧美一区激情| 欧美xxxx在线观看| 亚洲欧美成人网| 久久久91精品国产| 一区二区三区欧美在线观看| 午夜精品在线观看| 亚洲久色影视| 午夜视频精品| 99天天综合性| 久久视频在线免费观看| 亚洲一级网站| 久久精品人人做人人爽电影蜜月| 亚洲乱码国产乱码精品精天堂| 一区二区三区色| 在线观看欧美日韩| 中文一区在线| 亚洲精品视频在线播放| 亚洲欧美中文另类| 日韩一级视频免费观看在线| 欧美呦呦网站| 亚洲欧美一区二区激情| 免费视频久久| 久久久久久一区| 欧美视频久久| 亚洲二区免费| 极品尤物久久久av免费看| 一本色道久久综合亚洲精品不| 怡红院精品视频在线观看极品| 一区二区三区av| 99re8这里有精品热视频免费| 午夜亚洲影视| 亚洲女同在线| 欧美日韩三级| 亚洲激情国产| 亚洲欧洲精品一区二区精品久久久| 午夜精品国产| 亚洲欧美一区二区三区极速播放| 欧美日韩国产在线| 亚洲国产第一| 亚洲国产一区在线| 久久久蜜桃精品| 久久久五月婷婷| 国产一区二区三区在线免费观看| 亚洲一区二区成人| 亚洲在线一区二区| 欧美色123| 一区二区国产日产| 亚洲天天影视| 欧美日本在线| 亚洲免费高清视频| 亚洲色无码播放| 欧美性大战久久久久| 夜夜夜精品看看| 一区二区激情视频| 欧美另类视频在线| 亚洲视频第一页| 亚洲一区bb| 国内视频精品| 久久狠狠婷婷| 国产精品日韩精品欧美精品| 欧美不卡高清| 在线观看视频一区| 久久久久久久久久久久久女国产乱| 小黄鸭精品密入口导航| 国产精品视频网站| 欧美亚洲专区| 欧美成人激情在线| 日韩午夜免费视频| 欧美精品v日韩精品v国产精品| 亚洲久久成人| 欧美在线观看视频一区二区三区| 国产欧美日韩免费| 久久丁香综合五月国产三级网站| 久久婷婷久久| 亚洲精品一区二区三区不| 亚洲国产精彩中文乱码av在线播放| 国产精品99久久不卡二区| 亚洲精品日本| 国产在线拍偷自揄拍精品| 久久国产福利国产秒拍| 欧美成人综合一区| 一区二区三区高清在线 | 久久综合狠狠综合久久综合88| 老色鬼精品视频在线观看播放| 亚洲福利在线视频| 欧美日韩亚洲综合一区| 亚洲欧美一区二区三区极速播放 | 亚洲一区二区网站| 蜜桃av久久久亚洲精品| 在线一区二区视频| 红桃视频一区| 国产精品ⅴa在线观看h| 久久久久久夜| 亚洲一区二区三区四区五区黄| 麻豆免费精品视频| 亚洲制服丝袜在线| 1024亚洲| 国产精品久久午夜夜伦鲁鲁| 久久婷婷丁香| 亚洲午夜av电影| 亚洲第一区中文99精品| 久久国产精品久久精品国产| 日韩午夜中文字幕| 雨宫琴音一区二区在线| 国产精品丝袜白浆摸在线| 欧美激情综合五月色丁香| 久久久噜噜噜久久久| 午夜精品久久久久久久99水蜜桃 | 久久久免费av| 先锋影音一区二区三区| 一个色综合导航| 亚洲国内自拍| 亚洲国产成人av在线| 美玉足脚交一区二区三区图片|