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

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>
            欧美韩日一区| 欧美成人性生活| 日韩亚洲精品在线| 欧美一区精品| 欧美在线看片| 欧美久久久久久久| 欧美96在线丨欧| 韩日精品中文字幕| 亚洲综合精品| 亚洲视频在线观看三级| 欧美成人精品高清在线播放| 久久一区二区三区av| 国产自产女人91一区在线观看| 亚洲视频免费在线| 中文精品视频一区二区在线观看| 欧美成人在线免费观看| 欧美成人自拍| 在线高清一区| 噜噜噜91成人网| 欧美chengren| 亚洲日本va在线观看| 久久影院亚洲| 亚洲国产另类久久久精品极度| 国产亚洲欧洲997久久综合| 亚洲欧美日韩中文在线制服| 亚洲欧美激情诱惑| 国产乱码精品一区二区三区不卡| 亚洲视频国产视频| 欧美影视一区| 国一区二区在线观看| 久久久成人网| 亚洲国产欧美一区二区三区久久| 亚洲激情欧美| 欧美精品一区二区三区四区| 亚洲人午夜精品| 亚洲嫩草精品久久| 国产九九精品视频| 久久精品天堂| 欧美激情一区二区三区不卡| 夜夜嗨av色综合久久久综合网| 欧美人与性禽动交情品| 亚洲深夜激情| 久久深夜福利免费观看| 最近看过的日韩成人| 欧美日本精品一区二区三区| 中文久久精品| 久久精品国产清高在天天线| 亚洲东热激情| 欧美午夜片在线观看| 午夜视黄欧洲亚洲| 欧美电影专区| 亚洲一区在线免费| 精品96久久久久久中文字幕无| 久久久久久久久岛国免费| 亚洲高清不卡在线| 午夜精彩国产免费不卡不顿大片| 合欧美一区二区三区| 欧美激情精品久久久久久| 亚洲调教视频在线观看| 免费毛片一区二区三区久久久| 99国产欧美久久久精品| 国产日韩专区| 欧美另类综合| 久久国产99| 亚洲最新视频在线播放| 久久美女性网| 亚洲一级二级| 亚洲国产精品v| 国产精品欧美久久| 欧美xx69| 欧美在线999| 99国产精品国产精品毛片| 欧美波霸影院| 欧美一区二区三区在线观看 | 欧美日韩免费观看中文| 欧美一激情一区二区三区| 亚洲人成毛片在线播放女女| 欧美在线观看网站| 亚洲午夜一区二区三区| 亚洲国产专区校园欧美| 国产午夜久久久久| 欧美性猛交一区二区三区精品| 久久亚裔精品欧美| 午夜精品免费在线| 亚洲视频在线观看| 999在线观看精品免费不卡网站| 久久激五月天综合精品| 亚洲欧美国产高清va在线播| 亚洲裸体视频| 亚洲国产日韩欧美一区二区三区| 国产日本亚洲高清| 欧美亚一区二区| 欧美日韩国产大片| 欧美www在线| 女人香蕉久久**毛片精品| 久久久久久自在自线| 欧美一区二区免费| 欧美一区二区私人影院日本| 亚洲线精品一区二区三区八戒| 亚洲精品永久免费| 亚洲国产精品悠悠久久琪琪| 欧美成人自拍| 欧美激情亚洲激情| 亚洲成人在线免费| 亚洲国产精品第一区二区三区| 国产女优一区| 国产欧美精品va在线观看| 国产日韩一区二区| 国产日韩欧美中文| 国产婷婷色一区二区三区四区| 国产日韩综合| 黄色精品一区二区| 亚洲黄页一区| 99天天综合性| avtt综合网| 国产精品三上| 国产伦精品一区二区三区免费迷| 国产精品视频一二| 国产欧美精品日韩精品| 国产一区再线| 在线观看三级视频欧美| 亚洲精品日韩精品| 中文欧美字幕免费| 欧美一区二区三区视频免费| 久久久久久久久伊人| 老司机精品福利视频| 亚洲电影天堂av| 99在线精品观看| 先锋资源久久| 免播放器亚洲| 欧美午夜在线| 尤物在线观看一区| 亚洲一区二区成人在线观看| 午夜精品一区二区三区在线视| 久久黄色级2电影| 欧美激情区在线播放| 99精品免费视频| 久久成人免费日本黄色| 欧美韩日一区二区| 国产九九精品| 日韩亚洲综合在线| 久久精品亚洲| 亚洲精品九九| 久久都是精品| 欧美视频一区在线| 激情视频一区二区三区| 一区二区三区成人| 久久这里有精品视频| 欧美肥婆bbw| 亚洲综合色丁香婷婷六月图片| 久久久青草青青国产亚洲免观| 欧美日韩亚洲视频一区| 国产自产2019最新不卡| 亚洲午夜国产成人av电影男同| 久久男女视频| 一本综合精品| 美日韩精品免费观看视频| 国产精品一区二区久久久久| 亚洲激情网站| 久久精品亚洲一区二区| 亚洲乱码国产乱码精品精可以看 | 亚洲国产精品国自产拍av秋霞| 亚洲欧美久久久| 亚洲国产一二三| 久久精品官网| 国产精品日韩| 亚洲网址在线| 亚洲人线精品午夜| 久久久久久夜| 国产一区日韩一区| 亚洲影院免费观看| 最新日韩欧美| 麻豆精品传媒视频| 影音先锋另类| 久久亚洲精品一区二区| 亚洲欧美日韩综合aⅴ视频| 欧美日韩中文字幕日韩欧美| 亚洲人成欧美中文字幕| 欧美成人精品影院| 久久亚洲国产精品一区二区| 国产亚洲一区二区在线观看| 欧美伊人久久久久久午夜久久久久| 一本久久精品一区二区| 欧美精品在线观看| 亚洲免费黄色| 亚洲激情六月丁香| 欧美激情精品| 一本色道久久综合狠狠躁篇怎么玩| 亚洲第一网站| 欧美丰满高潮xxxx喷水动漫| 在线日韩成人| 欧美freesex8一10精品| 老司机精品久久| 亚洲国产精品视频| 欧美激情按摩在线| 免费成人黄色片| 99成人免费视频| 一区二区欧美在线| 国产欧美精品一区aⅴ影院| 久久riav二区三区|