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

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

一 信號的種類

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

可靠信號就是實時信號, 那些從UNIX系統繼承過來的信號都是非可靠信號, 表現在信號

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

SIGRTMIN的都是非可靠信號.

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

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

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

 

關于可靠信號, 還可以參考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, 可以列出系統支持的所有信號:

 

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使用系統調用 signal 來安裝信號


#include <signal.h>

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

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

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


經典安裝方式:

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

    signal(SIGINT, sig_handler);

}

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


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

處理期間, 仍能對后繼信號做出反應, 往往在handler的第一條語句再次調用 signal


sig_handler(ing signum)

{

    /* 重新安裝信號 */

    signal(signum, sig_handler);

    ......

}

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

信號之前產生, 這次信號就會執行默認動作, 而不是sig_handler. 這種問題是不可預料的.


使用庫函數 sigaction  來安裝信號

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

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

動作為止. 這就克服了古老的 signal 調用存在的問題


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


經典安裝方式:


struct sigaction action, old_action;



/* 設置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 實現的庫函數: signal

sigaction 自然強大, 但安裝信號很繁瑣, 目前linux中的signal()是通過sigation()函數

實現的,因此,即使通過signal()安裝的信號,在信號處理函數的結尾也不必

再調用一次信號安裝函數。

 

三 如何屏蔽信號

 

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

解除屏蔽后, 信號將被遞送, 不會丟失. 相關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()函數能夠根據參數how來實現對信號集的操作,操作主要有三種:

* SIG_BLOCK 在進程當前阻塞信號集中添加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);

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

    sleep(
2);

    
return 0;
}

 運行結果:

 

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

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

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

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


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

在信號的handler執行期間, 系統將自動屏蔽此信號, 但如果

還想屏蔽其它信號怎么辦?  可以利用 struct sigaction 結構體

的 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內將屏蔽掉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;  
  
    
/* 設置SIGINT */  
    action.sa_handler 
= sig_handler;  
    sigemptyset(
&action.sa_mask);  
    
/* 安裝handler的時候, 設置在handler 
     * 執行期間, 屏蔽掉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);  
    }  
  
    
/* 設置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;  
}

 

運行結果:

 

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

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

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

 

 

四 如何獲取未決信號

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


int sigsuspend(const sigset_t *mask));

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

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

 

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;

    
/* 設置信號的handler */
    signal(MYSIGNAL, sig_handler);

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

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

    
/* 檢查當前的未決信號 */
    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;
}

  這個程序有兩個版本:

可靠信號版本, 運行結果:

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

發送兩次可靠信號, 最終收到兩次信號


非可靠信號版本, 運行結果:

 

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

  發送兩次非可靠信號, 最終只收到一次

 

五 被中斷了的系統調用

一些IO系統調用執行時, 如 read 等待輸入期間, 如果收到一個信號,

系統將中斷read, 轉而執行信號處理函數. 當信號處理返回后, 系統

遇到了一個問題: 是重新開始這個系統調用, 還是讓系統調用失敗?


早期UNIX系統的做法是, 中斷系統調用, 并讓系統調用失敗, 比如read

返回 -1, 同時設置 errno 為 EINTR


中斷了的系統調用是沒有完成的調用, 它的失敗是臨時性的, 如果再次調用

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


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;

    }

}


這樣做邏輯比較繁瑣, 事實上, 我們可以從信號的角度

來解決這個問題,  安裝信號的時候, 設置 SA_RESTART

屬性, 那么當信號處理函數返回后, 被該信號中斷的系統

調用將自動恢復. 

 

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:不設置SA_RESTART屬性 
         * 版本2:設置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, 不設置 SA_RESTART 屬性 :

 

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

在 read 等待數據期間, 按下ctrl + c, 觸發 SIGINT 信號, 

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


版本2, 設置 SA_RESTART 屬性:

 

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

 handler 返回后, read 系統調用被恢復執行, 繼續等待數據.

 

 

六 非局部控制轉移


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()會保存目前堆棧環境,然后將目前的地址作一個記號,

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

然后還原堆棧,繼續程序好執行。 


setjmp調用有點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 的唯一區別是: setjmp 不一定會恢復信號集合,

而sigsetjmp可以保證恢復信號集合

 

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;

    
/* 設置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);
    }

    
/* 設置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;
}

 

運行結果: 

 

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

 

 

七 信號的生命周期

 

從信號發送到信號處理函數的執行完畢

對于一個完整的信號生命周期(從信號發送到相應的處理函數執行完畢)來說,

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

信號誕生;信號在進程中注冊完畢;信號在進程中的注銷完畢;信號處理函數執行完畢。


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

信號"誕生"。信號的誕生指的是觸發信號的事件發生

(如檢測到硬件異常、定時器超時以及調用信號發送函數

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

進程的task_struct結構中有關于本進程中未決信號的數據成員:

struct sigpending pending:

struct sigpending{

struct sigqueue *head, **tail;

sigset_t signal;

};


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

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

的每個sigqueue結構刻畫一個特定信號所攜帶的信息,并指向下一個

sigqueue結構:

struct sigqueue{

struct sigqueue *next;

siginfo_t info;

}


信號的注冊

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

(sigpending結構的第二個成員sigset_t signal),

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

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

當一個實時信號發送給一個進程時,不管該信號是否已經在進程中注冊,

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

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

當一個非實時信號發送給一個進程時,如果該信號已經在進程中注冊,

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

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

一個非實時信號誕生后,

(1)、如果發現相同的信號已經在目標結構中注冊,則不再注冊,對于進程來說,

相當于不知道本次信號發生,信號丟失.

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


信號的注銷。

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

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

信號等待處理且該信號沒有被進程阻塞,則在運行相應的信號處理函數前,

進程會把信號在未決信號鏈中占有的結構卸掉。是否將信號從進程未決信號集

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

號信息鏈中最多只占用一個sigqueue結構,因此該結構被釋放后,應該把信

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

未決信號信息鏈中占用多個sigqueue結構,因此應該針對占用sigqueue結構

的數目區別對待:如果只占用一個sigqueue結構(進程只收到該信號一次),

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

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

進程在執行信號相應處理函數之前,首先要把信號在進程中注銷。


信號生命終止。

進程注銷信號后,立即執行相應的信號處理函數,執行完畢后,

信號的本次發送對進程的影響徹底結束。

 

八 關于可重入函數

 

在信號處理函數中應使用可重入函數。

信號處理程序中應當使用可重入函數

(注:所謂可重入函數是指一個可以被多個任務調用的過程,

任務在調用時不必擔心數據是否會出錯)。因為進程在收到信號

后,就將跳轉到信號處理函數去接著執行。如果信號處理函數中

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

不應該被修改的數據,這樣進程從信號處理函數中返回接著執行時,

可能會出現不可預料的后果。不可再入函數在信號處理函數中被視為

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

(1)使用靜態的數據結構,如getlogin(),gmtime(),getgrgid(),

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

(2)函數實現時,調用了malloc()或者free()函數;

(3)實現時使用了標準I/O函數的。The Open Group視下列函數為可再入的:

    _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()。


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

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

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

因為不能保證緊接著兩個函數的其它調用是安全的。


轉自:http://kenby.iteye.com/blog/1173862
posted on 2013-01-13 12:31 小果子 閱讀(617) 評論(0)  編輯 收藏 引用 所屬分類: 學習筆記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>
            aa级大片欧美三级| 亚洲欧美清纯在线制服| 国产婷婷成人久久av免费高清 | 亚洲美女在线国产| 国产一区二区日韩| 中文精品视频| 宅男66日本亚洲欧美视频| 久久精品一区二区三区不卡| 性欧美videos另类喷潮| 欧美午夜片在线观看| 欧美大尺度在线| 韩国三级电影久久久久久| 午夜精品久久99蜜桃的功能介绍| 亚洲一级黄色片| 欧美日韩国产美| 91久久精品国产91性色| 亚洲黄色小视频| 久久综合色8888| 欧美大成色www永久网站婷| 精品粉嫩aⅴ一区二区三区四区| 香港成人在线视频| 欧美在线视频一区二区| 国产日韩欧美精品在线| 香蕉久久夜色| 久久女同精品一区二区| 一色屋精品视频免费看| 久久人人爽人人爽| 欧美国产日韩精品| 亚洲美女91| 欧美日韩精品在线观看| 一区二区三区偷拍| 欧美影院精品一区| 黄色一区二区在线观看| 免费成人av在线| 亚洲精品国产精品国自产观看浪潮 | 午夜亚洲性色福利视频| 久久国产精品久久久久久电车| 国产九九精品| 久久国产成人| 亚洲成色999久久网站| 99re视频这里只有精品| 国产精品久久午夜夜伦鲁鲁| 午夜久久福利| 欧美电影免费观看高清| 日韩写真视频在线观看| 国产精品久久久一本精品| 性高湖久久久久久久久| 欧美福利专区| 一区二区欧美在线观看| 国产视频亚洲| 欧美精品二区三区四区免费看视频| 一区二区三区精品国产| 久久久久久9| 日韩视频第一页| 国产午夜精品久久| 欧美成人在线免费视频| 亚洲在线一区二区| 欧美高清视频一区| 欧美一区2区视频在线观看| 亚洲高清久久网| 国产精品伦一区| 男女av一区三区二区色多| 亚洲午夜av| 亚洲黄色影院| 久久一区亚洲| 亚洲欧美日韩系列| 亚洲精品国产无天堂网2021| 国产日韩欧美日韩大片| 欧美极品在线视频| 久久久91精品国产一区二区精品| 99精品国产一区二区青青牛奶| 噜噜噜91成人网| 亚洲欧美日韩一区二区三区在线观看 | 亚洲美女免费精品视频在线观看| 国产精品揄拍500视频| 欧美激情一区二区久久久| 欧美一区二区视频观看视频| 亚洲精品中文字幕女同| 欧美不卡视频| 久久久久久久999精品视频| 亚洲一区二区少妇| 日韩一区二区免费高清| 亚洲国产成人一区| 国模叶桐国产精品一区| 国产精品美女一区二区| 欧美日韩一视频区二区| 欧美国产精品人人做人人爱| 久久国产天堂福利天堂| 午夜精品久久久久久99热软件| 亚洲精品中文在线| 亚洲国产毛片完整版| 女女同性女同一区二区三区91| 久久黄色网页| 久久精品成人| 久久精品女人天堂| 欧美专区18| 久久精品2019中文字幕| 欧美在线播放视频| 欧美在线视频不卡| 久久国产精品一区二区三区四区| 亚洲免费在线| 欧美一区二区三区男人的天堂 | 亚洲图片欧美日产| 一区二区三区导航| 夜夜嗨av一区二区三区四区| 亚洲精品中文字幕女同| 日韩视频在线播放| 一本一本久久a久久精品综合麻豆| 日韩午夜在线观看视频| 亚洲久久一区| 中文国产一区| 欧美一二三区精品| 久久国产精品第一页| 久久久久久久久久久一区| 久久漫画官网| 欧美大学生性色视频| 欧美日韩视频在线一区二区| 欧美天堂亚洲电影院在线观看 | 久久国产精品网站| 久久久久久欧美| 免费亚洲电影在线观看| 欧美精品系列| 国产精品嫩草久久久久| 国产在线观看一区| 亚洲国产日韩欧美在线99| 99精品视频免费观看| 亚洲免费在线| 久久一区二区精品| 亚洲国产精品久久久久秋霞蜜臀| 亚洲精品国产视频| 亚洲性夜色噜噜噜7777| 久久久久综合网| 欧美日韩999| 国产亚洲欧美日韩日本| 亚洲精品国产精品国自产在线 | 91久久国产精品91久久性色| 艳妇臀荡乳欲伦亚洲一区| 午夜欧美大尺度福利影院在线看 | 欧美国产日韩亚洲一区| 日韩视频免费看| 欧美怡红院视频一区二区三区| 欧美成人蜜桃| 国产日本欧美一区二区三区在线| 亚洲国产成人tv| 亚洲一区免费网站| 欧美国产亚洲精品久久久8v| 亚洲视频在线一区观看| 久久婷婷成人综合色| 欧美亚洲成人网| 亚洲激情国产| 久久久久9999亚洲精品| 日韩西西人体444www| 久久色在线播放| 国产精品一卡二卡| 日韩图片一区| 久久综合一区二区三区| 中文在线资源观看视频网站免费不卡| 久久香蕉国产线看观看av| 国产精品看片你懂得| 亚洲伦理在线| 免费成人在线观看视频| 亚洲影院色在线观看免费| 欧美精品久久久久久久| 韩日在线一区| 欧美在线资源| 亚洲午夜精品国产| 欧美日韩免费在线观看| 亚洲精品乱码视频| 欧美成年人网站| 久久精品国产免费观看| 国产日产欧产精品推荐色| 亚洲影院免费| 中日韩美女免费视频网址在线观看 | 欧美成人午夜激情视频| 国产综合视频在线观看| 欧美在线视频在线播放完整版免费观看 | 99这里只有精品| 欧美精品一级| 99精品国产高清一区二区| 欧美福利网址| 另类专区欧美制服同性| 精品91免费| 免费日韩成人| 玖玖综合伊人| 亚洲欧洲精品天堂一级| 欧美成年人网站| 麻豆精品在线视频| 亚洲国产日韩欧美在线图片| 免费成人av在线| 久久综合久色欧美综合狠狠 | 午夜天堂精品久久久久| 国产九色精品成人porny| 午夜精品理论片| 午夜久久电影网| 国产亚洲欧美日韩美女| 另类国产ts人妖高潮视频| 乱人伦精品视频在线观看| 亚洲人成绝费网站色www| 91久久精品久久国产性色也91| 欧美精品免费看|