日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UNIX再学习 -- 信号处理

發布時間:2025/3/15 编程问答 7 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UNIX再学习 -- 信号处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、鬧鐘和睡眠

1、函數 alarm

#include <unistd.h> unsigned int alarm(unsigned int seconds); 返回值:返回 0 或先前所設鬧鐘的剩余秒數

(1)函數功能

使用 alarm 函數可以設置一個定時器(鬧鐘時間),在將來的某個時刻該定時器會超時。當定時器超時時,產生 SIGALRM 信號。如果忽略或不捕捉此信號,則其默認動作是終止調用該 alarm 函數的進程。

(2)參數解析

參數 seconds 的值是產生信號 SIGALRM 需要經過的時鐘秒數。當這個時刻到達時,信號由內核產生,由于進程調度的延遲,所以進程得到控制從而能夠處理該信號還需要一個時間間隔。

(3)函數解析

每個進程只能有一個鬧鐘時間。如果在調用 alarm 時,之前已為該進程注冊的鬧鐘時間還沒有超時,則該鬧鐘時間的余值作為本次 alarm 函數調用的值返回。以前注冊的鬧鐘時間則被新值代替。 如果有以前注冊的尚未超過的鬧鐘時間,而且本次調用的 seconds 值是 0,則取消以前的鬧鐘時間,其余留值仍作為 alarm 函數的返回值。 雖然 SIGALRM 的默認動作是終止進程,但是大多數使用鬧鐘的進程捕捉此信號。如果此時進程要終止,則在終止之前它可以執行所需的清理操作。如果我們想捕捉 SIGALRM 信號,則必須在調用 alarm 之前安裝該信號的處理程序。如果我們先調用 alarm,然后在我們能夠安裝 SIGALRM 處理程序之前已接到該信號,那么進程將終止。

(4)示例說明

//示例一 //alarm函數的使用 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h>void fa(int signo) {printf("捕獲到了信號%d\n",signo);//設置1秒后發送信號alarm(1); }int main(void) {//設置SIGALRM信號進行自定義處理signal(SIGALRM,fa);//設置5秒后發送SIGALRM信號int res = alarm(5);printf("res = %d\n",res);//0sleep(2);//重新修改為10秒后發送SIGALRM信號res = alarm(10);printf("res = %d\n",res); //3/*sleep(3);//重新設置為0秒后,取消之前的鬧鐘res = alarm(0);printf("res = %d\n",res); //7*/while(1);return 0; } 輸出結果: res = 0 res = 3 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 捕獲到了信號 14 //示例二 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <time.h>void sigalrm (int signum) {time_t t = time (NULL);struct tm *it = localtime (&t);printf ("\n%02d:%02d:%02d 按回車鍵退出\n", it->tm_hour, it->tm_min, it->tm_sec);alarm (1); }int main (void) {if (signal (SIGALRM, sigalrm) == SIG_ERR)perror ("signal"), exit (1);sigalrm (SIGALRM);getchar ();return 0; } 輸出結果: 14:07:37 按回車鍵退出14:07:38 按回車鍵退出14:07:39 按回車鍵退出14:07:40 按回車鍵退出

(5)示例解析

示例一,alarm 設置 5 秒結束后,發送 SIGALRM 信號,如果鬧鐘時間沒有結束,又設了鬧鐘,則返回剩余鬧鐘秒數。alarm 參數為 0,則取消鬧鐘。 示例二,sigalrm (SIGARLM);函數運行,執行到 alarm (1); 產生 SIGALRM 信號,觸發 signal。然后就開始循環。

2、函數 pause

#include <unistd.h> int pause(void); 成功阻塞,失敗返回 -1

(1)函數功能

pause 函數使調用進程掛起直至捕捉到一個信號。(無限睡眠)

(2)函數解析

該函數使調用 進程/線程 進入無時限的睡眠狀態,直到有信號終止了調用進程或被其捕獲。 如果有信號被調用進程捕獲,在信號處理函數返回以后,pause 函數才會返回,且返回值為 -1,同時置 errno 為 EINTR,表示阻塞的系統調用被信號中斷。 pause 函數要么不返回,要么返回失敗,不會返回成功。

(3)示例說明

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <errno.h>void sigint (int signo) {printf ("\n中斷符號被發送\n"); }int main (void) {if (signal (SIGINT, sigint) == SIG_ERR)perror ("signal"), exit (1);printf ("按 ctrl+c 繼續\n");if (pause () != -1 && errno != EINTR)perror ("pause"), exit (1);printf ("進程繼續\n");return 0; } 輸出結果: 按 ctrl+c 繼續 ^C 中斷符號被發送 進程繼續

(4)示例解析

當有信號被當前進程捕獲,在信號處理函數返回以后,pause函數返回,且返回值為-1,同時置errno為EINTR,表示阻塞的系統調用被信號中斷。

3、函數 sleep

#include <unistd.h>unsigned int sleep(unsigned int seconds); 返回 0 或剩余秒數

(1)函數功能

有限睡眠

(2)參數解析

參數 seconds 以秒為單位的睡眠時限。?

(3)函數解析

該函數使調用進程/線程睡眠 seconds 秒,除非有信號終止了調用進程或被其捕獲 如果有信號被調用進程捕獲,在信號處理函數返回以后,sleep 函數才會返回,且返回值為剩余的秒數,否則該函數將返回 0,表示睡眠充足。如果由于捕獲到某個信號 sleep 提早返回時,返回值是未休眠完的秒數(所要求的時間減去實際休眠時間)。

(4)示例說明

#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <errno.h>void sigint (int signo) {printf ("\n中斷符號被發送\n"); }int main (void) {if (signal (SIGINT, sigint) == SIG_ERR)perror ("signal"), exit (1);printf ("按 ctrl+c 繼續\n");int res = sleep (60);if (res)printf ("進程被提前%d秒叫醒\n", res);printf ("進程繼續\n");return 0; } 輸出結果: 按 ctrl+c 繼續 ^C 中斷符號被發送 進程被提前57秒叫醒 進程繼續

(5)sleep 函數簡單實現

#include "apue.h"static void sig_alrm(int signo) {/* nothing to do, just returning wakes up sigsuspend() */ }unsigned int my_sleep(unsigned int seconds) {struct sigaction newact, oldact;sigset_t newmask, oldmask, suspmask;unsigned int unslept;/* set our handler, save previous information */newact.sa_handler = sig_alrm;sigemptyset(&newact.sa_mask);newact.sa_flags = 0;sigaction(SIGALRM, &newact, &oldact);/* block SIGALRM and save current signal mask */sigemptyset(&newmask);sigaddset(&newmask, SIGALRM);sigprocmask(SIG_BLOCK, &newmask, &oldmask);alarm(seconds);suspmask = oldmask;/* make sure SIGALRM isn't blocked */sigdelset(&suspmask, SIGALRM);/* wait for any signal to be caught */sigsuspend(&suspmask);/* some signal has been caught, SIGALRM is now blocked */unslept = alarm(0);/* reset previous action */sigaction(SIGALRM, &oldact, NULL);/* reset signal mask, which unblocks SIGALRM */sigprocmask(SIG_SETMASK, &oldmask, NULL);return(unslept); }int main (void) {my_sleep (10);printf ("hello world!\n");return 0; } 輸出結果: hello world!

4、函數 nanosleep

#include <time.h> int nanosleep(const struct timespec *req, struct timespec *rem); 返回值:若休眠到要求的時間,返回 0,若出錯,返回 -1struct timespec {time_t ?tv_sec; ? ? ? ? /* seconds */long ? ?tv_nsec; ? ? ? ?/* nanoseconds */ };

(1)函數功能

nanosleep 函數與 sleep 函數類似,但是提供了納秒級的精度

(2)參數解析

這個函數掛起調用進程,直到要求的時間已經超時或者某個信號中斷了該函數。 req 參數用秒和納秒指定了需要休眠的時間長度。如果某個信號中斷了休眠間隔,進程并沒有終止,rem 參數指向的 timespec 結構就會被設置為未休眠完的時間長度。如果對未休眠完的時間并不感興趣,可以把該參數置為 NULL。
如果系統并不支持納秒這一精度,要求的時間就會取整。因為,nanosleep 函數并不涉及產生任何信號,所以不需要擔心與其函數的交互。 參看:C語言再學習 -- 時間函數

(3)示例說明

#include <stdio.h> #include <time.h> #include <stdlib.h> #include <sys/time.h> int main (void) {struct timespec req, rem;rem.tv_sec = 0; rem.tv_nsec = 0; req.tv_sec = 0; req.tv_nsec = 1000000; int res = 0;struct timeval start,end; gettimeofday( &start, NULL ); /*測試起始時間*/ if (res = (nanosleep (&req, &rem)) == -1)perror ("nanosleep"), exit (1);gettimeofday( &end, NULL ); /*測試終止時間*/ int timeuse = (end.tv_usec - start.tv_usec); printf("運行時間為:%d us\n",timeuse); return 0; } 輸出結果: 運行時間為:1173 us

5、sleep、usleep 和 nanosleep 區別

參看:linux下nanosleep() & sleep()的區別 參看:關于短延遲 sleep usleep nanosleep select 時間單位還有:秒(s)、毫秒(ms)、微秒 (μs)、納秒(ns)、皮秒(ps)、飛秒(fs)、阿秒、渺秒 ? ?? usleep 和 sleep 區別在于精度,ulseep 為 微妙級,sleep 為秒級。 sleep() 和 nanosleep() 都是使進程睡眠一段時間后被喚醒,但是二者的實現完全不同。
Linux 中并沒有提供系統調用 sleep(),sleep() 是在庫函數中實現的,它是通過調用 alarm() 來設定報警時間,調用sigsuspend() 將進程掛起在信號 SIGALARM 上。
nanosleep() 則是 Linux中 的系統調用
,它是使用定時器來實現的,該調用使調用進程睡眠,并往定時器隊列上加入一個 timer_list 型定時器,time_list 結構里包括喚醒時間以及喚醒后執行的函數,通過 nanosleep() 加入的定時器的執行函數僅僅完成喚醒當前進程的功能。系統通過一定的機制定時檢查這些隊列(比如通過系統調用陷入核心后,從核心返回用戶態前,要檢查當前進程的時間片是否已經耗盡,如果是則調用 schedule() 函數重新調度,該函數中就會檢查定時器隊列,另外慢中斷返回前也會做此檢查),如果定時時間已超過,則執行定時器指定的函數喚醒調用進程。當然,由于系統時間片可能丟失,所以 nanosleep() 精度也不是很高。

二、信號集

1、什么是信號集

顧名思義,多個信號組成的信號集合謂之信號集。 系統內核用 sigset_t 類型表示信號集。sigset_t 類型是一個結構體,但該結構體中只有一個成員,是一個包含 32 個元素的整數數組。 ?/usr/include/i386-linux-gnu/bits/sigset.h 中有如下類型定義: /* A `sigset_t' has a bit for each signal. */# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) typedef struct{unsigned long int __val[_SIGSET_NWORDS];} __sigset_t; 可以把 sigset_t 類型看成一個由 1024 個二進制位組成的大整數。其中的每一位對應一個信號,其實目前遠沒有那么多信號。某位為 1 就表示信號集中有此信號,反之為 0 就是無此信號。當需要同時操作多個信號時,常以 sigset_t 作為函數的參數或返回值的類型。

2、信號集函數

#include <signal.h> int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signum); int sigdelset(sigset_t *set, int signum); 這 4 個函數返回值:若成功,返回 0,;若出錯,返回 -1 int sigismember(const sigset_t *set, int signum); 返回值:若真,返回 1;若假,返回 0

(1)函數 sigemptyset

清空信號集,即將信號集的全部信號位清 0. 例如: sigset_t sigset; if (sigemptyset (&sigset) == -1)perror ("sigemptyset"), exit (1);

(2)函數 sigfillset

填滿信號集,即將信號集的全部信號位置 1. 例如: sigset_t sigset; if (sigfillset (&sigset) == -1)perror ("sigfillset"), exit (1);

(3)函數 sigaddset

加入信號,即將信號集中與指定信號編號對應的信號位置 1. 例如: if (sigaddset (&sigset, SIGINT))perror ("sigaddset"), exit (1);

(4)函數 sigdelset

刪除信號,即將信號集中與指定信號編號對應的信號位清 0. 例如: if (sigdelest (&sigset, SIGINT))perror ("sigdelset"), exit (1);

(5)函數 sigismember

判斷信號集中是否有某信號,即檢查信號集中與指定信號編號對應的信號位是否為 1. 例如: if (sigismember (&sigset, SIGINT) == 1)printf ("信號集中有 SIGINT 信號\n");

(6)示例說明

//信號集的操作 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h>int main(void) {sigset_t set;printf("set = %lu\n",set);printf("sizeof(sigset_t) = %d\n",sizeof(sigset_t));//清空信號集sigemptyset(&set);printf("set = %lu\n",set);//0//增加信號到信號集中sigaddset(&set,2);// 0000 0010 => 1*2 = 2printf("set = %lu\n",set);//2sigaddset(&set,3);// 0000 0110 => 4+2 = 6printf("set = %lu\n",set);//6sigaddset(&set,7);// 0100 0110 => 64+4+2 = 70printf("set = %lu\n",set);//70//從信號集中刪除信號3sigdelset(&set,3);// 0100 0010 => 64 + 2 = 66printf("set = %lu\n",set);//66//判斷信號是否存在if(sigismember(&set,2)){printf("信號2存在\n");}if(sigismember(&set,3)){printf("信號3存在\n");}if(sigismember(&set,7)){printf("信號7存在\n");}//填滿信號集sigfillset(&set);printf("set = %lu\n",set);//很大的數return 0; } 輸出結果: set = -1078591106 sizeof(sigset_t) = 128 set = 0 set = 2 set = 6 set = 70 set = 66 信號2存在 信號7存在 set = 2147483647

3、信號集函數實現 (了解)

#include <signal.h> #include <errno.h>/** <signal.h> usually defines NSIG to include signal number 0.*/ #define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG)int sigaddset(sigset_t *set, int signo) {if (SIGBAD(signo)) {errno = EINVAL;return(-1);}*set |= 1 << (signo - 1); /* turn bit on */return(0); }int sigdelset(sigset_t *set, int signo) {if (SIGBAD(signo)) {errno = EINVAL;return(-1);}*set &= ~(1 << (signo - 1)); /* turn bit off */return(0); }int sigismember(const sigset_t *set, int signo) {if (SIGBAD(signo)) {errno = EINVAL;return(-1);}return((*set & (1 << (signo - 1))) != 0); }

三、信號屏蔽

1、遞送、未決與掩碼

當信號產生時,系統內核會在其所維護的進程表中,為特定的進程設置一個與該信號相對應的標志位,這個過程就叫做遞送 信號從產生到完成遞送之間存在一定的時間間隔,處于這段時間間隔中的信號狀態稱為未決 每個進程都有一個信號掩碼,它實際上是一個信號集,位于該信號集中的信號一旦產生,并不會被遞送給相應的進程,而是會被阻塞在未決狀態。 在信號處理函數執行期間,這個正在被處理的信號總是處于信號掩碼中,如果又有該信號產生,則會被阻塞,直到上一個針對該信號的處理過程結束以后才會被遞送。 當進程正在執行類似更新數據庫這樣的敏感任務時,可能不希望被某些信號中斷。這時可以通過信號掩碼暫時屏蔽而非忽略掉這些信號,使其一旦產生即被阻塞于未決狀態,待特定任務完成后,再回過頭來處理這些信號。

2、設置掩碼與檢測未決

(1)設置調用進程的信號掩碼

#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 返回值:若成功,返回 0;若出錯,返回 -1

1》》參數解析

參數 how 為修改信號掩碼的方式,可取以下值 ? ? SIG_BLOCK ? ? ? ?將 sigset 中的信號加入當前信號掩碼 ? ? SIG_UNBLOCK ?從當前信號掩碼中刪除 sigset 中的信號 ? ? SIG_SETMASK ? 把 sigset 設置成當前信號掩碼 參數 sigset 為信號集,取 NULL 則忽略此參數 參數 oldset 為輸出原信號掩碼,取 NULL 則忽略此參數

2》》示例說明

#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h>int main() {sigset_t sigset;sigemptyset (&sigset);sigaddset (&sigset, SIGINT);sigaddset (&sigset, SIGQUIT);sigset_t oldset;if (sigprocmask (SIG_SETMASK, &sigset, &oldset) == -1){perror ("sigprocmask");exit (EXIT_FAILURE);}if (sigpending (&sigset) == -1){perror ("sigpending");exit (EXIT_FAILURE);}if (sigismember (&sigset, SIGINT) == 1)printf ("SIGINT信號未決\n");while (1)pause ();return 0; } 輸出結果: 按 ctrl+c 和 ctrl+\ 失效

(2)獲取調用進程的未決信號集

#include <signal.h> int sigpending(sigset_t *set); 返回值:成功返回 0,失敗返回 -1

1》》函數解析

sigpending 函數返回一信號集,對于調用進程而言,其中的各信號是阻塞不能遞送的,因而也一定是當前未決的。該信號集通過 set 參數返回。

2》》示例說明

#include "apue.h"static void sig_quit(int);int main(void) {sigset_t newmask, oldmask, pendmask;if (signal(SIGQUIT, sig_quit) == SIG_ERR)err_sys("can't catch SIGQUIT");/** Block SIGQUIT and save current signal mask.*/sigemptyset(&newmask);sigaddset(&newmask, SIGQUIT);if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)err_sys("SIG_BLOCK error");sleep(5); /* SIGQUIT here will remain pending */if (sigpending(&pendmask) < 0)err_sys("sigpending error");if (sigismember(&pendmask, SIGQUIT))printf("\nSIGQUIT pending\n");/** Restore signal mask which unblocks SIGQUIT.*/if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)err_sys("SIG_SETMASK error");printf("SIGQUIT unblocked\n");sleep(5); /* SIGQUIT here will terminate with core file */exit(0); }static void sig_quit(int signo) {printf("caught SIGQUIT\n");if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)err_sys("can't reset SIGQUIT"); } 輸出結果: ^\^\^\ SIGQUIT pending caught SIGQUIT SIGQUIT unblocked ^\^\退出 (核心已轉儲)

3》》示例解析

進程阻塞 SIGQUIT 信號,保存了當前信號屏蔽字(以便以后恢復),然后休眠 5 秒。在此期間所產生的退出信號 SIGQUIT 都被阻塞,不遞送至該進程,直到該信號不再被阻塞。在 5 秒休眠結束后,檢查該信號是否是未決的,然后將 SIGQUIT 設置為不再阻塞。

(3)可靠和不可靠信號的屏蔽

對于可靠信號,通過 sigprocmask 函數設置信號掩碼以后,每種被屏蔽信號中的每個信號都會被阻塞,并按先后順序排隊,一旦解除屏蔽,這些信號會被依次遞送。
對于不可靠信號,通過 sigprocmask 函數設置信號掩碼以后,每種被屏蔽信號中只有第一個會被阻塞,并在解除屏蔽后被遞送,其余的則全部丟失。

四、信號處理與發送

1、信號處理函數 sigaction

#include <signal.h> int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); 返回值:成功返回 0,失敗返回 -1

(1)函數功能

sigaction 函數的功能是檢查或修改(或檢查并修改)與指定信號相關聯的處理動作。此函數取代了 UNIX 早期版本使用的 signal 函數。可以理解為,是 signal 函數的增強版。

(2)參數解析

signum:信號編號act:信號行為oldact:輸出原信號行為,可置 NULL
當 signum 信號被遞送時,按 act 所描述的行為響應。若 oldact 非 NULL,則通過該參數輸出原來的響應行為。sigaction 函數通過信號行為結構類型 sigaction 來描述對一個信號的響應行為。struct sigaction { 1 void (*sa_handler)(int); =>函數指針,用于設置信號的處理方式,與signal函數中第二個參數相同,SIG_IGW,SIG_DFL函數名 2 void (*sa_sigaction)(int, siginfo_t */*結構體指針*/, void *);=>函數指針,作為第二種處理信號的方式 是否使用該處理方式,依賴與sa_flags的值 3 sigset_t sa_mask;=>用于設置在信號處理函數的執行期間,需要屏蔽的信號=>自動屏蔽與正在處理的信號相同的信號 4 int sa_flags;=>處理的標志 =>SA_SIGINFO 表示采用第二個函數指針處理信號=>SA_NODEFER 表示解除對相同信號的屏蔽=>SA_RESETHAND 表示自定義處理信號后恢復默認處理方式 5 void (*sa_restorer)(void); => 保留成員,暫時不是用,目前置NULL };其中第二個函數指針的第二個參數類型如下:
struct siginfo_t { pid_t si_pid; /* Sending process ID */ //發送信號進程的ID sigval_t si_value; /* Signal value */ //發送信號時的附加數據 };

(3)示例說明

示例一:增減信號掩碼

//使用sigaction函數處理信號 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h>void fa(int signo) {printf("捕獲到了信號%d\n",signo);sleep(5);printf("信號處理完畢\n"); }int main(void) {//定義結構體變量并且進行初始化struct sigaction action = {};//指定函數指針的初始值action.sa_handler = fa;//清空信號集,然后放入信號3sigemptyset(&action.sa_mask);sigaddset(&action.sa_mask,3);//設置處理信號的標志//解除對相同信號的屏蔽,信號2//action.sa_flags = SA_NODEFER;//自定義處理后恢復默認處理方式action.sa_flags = SA_RESETHAND;//使用sigaction對信號2自定義處理sigaction(2,&action,NULL);while(1);return 0; } 輸出結果: ^C捕獲到了信號2 ^\^\^\^\^\^\^\信號處理完畢 退出 (核心已轉儲)

示例二:一次性信號處理

#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h>void oldsigint(int signum) {printf ("\n%d進程:收到%d信號\n", getpid (), signum); }int main() {struct sigaction sigact = {};sigact.sa_handler = oldsigint;sigaddset (&sigact.sa_mask, SIGQUIT);sigact.sa_flags = SA_NODEFER | SA_RESETHAND;if (sigaction (SIGINT, &sigact, NULL) == -1){perror ("sigaction");exit (EXIT_FAILURE);}pause();return 0; } 輸出結果: ^C 2512進程:收到2信號 ^C

示例三:提供更多信息的信號處理函數

#include <stdio.h> #include <signal.h> #include <stdlib.h> #include <unistd.h>void newsigint (int signum, siginfo_t* siginf, void* reserved) {printf ("%d進程給我發了一個SIGINT信號\n", siginf->si_pid); }int main() {struct sigaction sigact = {};sigact.sa_sigaction = newsigint;sigaddset (&sigact.sa_mask, SIGQUIT);sigact.sa_flags = SA_NODEFER | SA_SIGINFO;if (sigaction (SIGINT, &sigact, NULL) == -1){perror ("sigaction");exit (EXIT_FAILURE);}pause();return 0; } 輸出結果: ^C0進程給我發了一個SIGINT信號

(4)用 sigaction 實現 signal 函數

#include <stdio.h> #include <signal.h> #include "apue.h" /* Reliable version of signal(), using POSIX sigaction(). */ Sigfunc * signal_my(int signo, Sigfunc *func) {struct sigaction act, oact;act.sa_handler = func;sigemptyset(&act.sa_mask);act.sa_flags = 0;if (signo == SIGALRM) { #ifdef SA_INTERRUPTact.sa_flags |= SA_INTERRUPT; #endif} else {act.sa_flags |= SA_RESTART;}if (sigaction(signo, &act, &oact) < 0)return(SIG_ERR);return(oact.sa_handler); }void fa (int signo) {printf ("捕獲到了信號%d\n", signo); }int main (void) {signal_my (2, fa); sleep (5);return 0; } 輸出結果: ^C捕獲到了信號2 另一個版本,可阻止被中斷的系統調用重啟動。#include "apue.h"Sigfunc * signal_intr(int signo, Sigfunc *func) {struct sigaction act, oact;act.sa_handler = func;sigemptyset(&act.sa_mask);act.sa_flags = 0; #ifdef SA_INTERRUPTact.sa_flags |= SA_INTERRUPT; #endifif (sigaction(signo, &act, &oact) < 0)return(SIG_ERR);return(oact.sa_handler); }

2、信號發送函數 sigqueue

#include <signal.h> int sigqueue(pid_t pid, int sig, const union sigval value); 返回值:成功返回 0;失敗返回 -1

(1)函數功能

表示向指定進程發送指定的信號和附加數據

(2)參數解析

pid:接收信號進程的 PID sig:信號編號 value:附加數據 注意,該參數的類型 sigval 是一個聯合: union sigval {int sival_int;//整數void *sival_ptr;//地址 };

(3)示例說明

//sigqueue函數和sigaction函數的使用 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <signal.h>void fa(int signo,siginfo_t* info,void* p) {printf("進程%d發送來了信號%d,附加數據是:%d\n",info->si_pid,signo,info->si_value); }int main(void) {//定義結構體變量進行初始化struct sigaction action = {};//給第二個函數指針進行初始化action.sa_sigaction = fa;//給處理標志進行賦值//表采用結構中第二個函數指針處理action.sa_flags = SA_SIGINFO;//使用sigaction對信號40自定義處理sigaction(40,&action,NULL);//創建子進程給父進程發信號和數據pid_t pid = fork();if(-1 == pid){perror("fork"),exit(-1);}if(0 == pid) //子進程{int i = 0;for(i = 0; i < 100; i++){//定義聯合進行初始化union sigval v;v.sival_int = i;//發送信號和附加數據sigqueue(getppid(),40,v);}sleep(1);exit(100);//終止子進程}//父進程等待處理信號和附加數據while(1);return 0; }輸出結果: 進程2721發送來了信號40,附加數據是:0 進程2721發送來了信號40,附加數據是:1 進程2721發送來了信號40,附加數據是:2 。。。。 進程2721發送來了信號40,附加數據是:97 進程2721發送來了信號40,附加數據是:98 進程2721發送來了信號40,附加數據是:99

五、函數 sigsetjmp 和 siglongjmp

暫時不講

六、 函數 sigsuspend

暫時不講

七、未講部分

中斷的系統調用 ?未講 可靠信號術語和語義 ?未講 函數 system ?未講 函數 clock_nanosleep ?未講 作業控制信號 ?未講 信號名和編號 ?未講 信號這一章,內容有點雜,好多東西沒有用過,所以不太熟悉。

總結

以上是生活随笔為你收集整理的UNIX再学习 -- 信号处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: www.69av.com| av手机网| 午夜精品一区 | 日韩成人高清视频 | 日韩淫视频| 国产日韩一区二区三区 | 日韩精品极品视频在线观看免费 | 秋霞在线观看秋 | 日本免费一区二区在线 | 香蕉视频国产在线观看 | 国产精品久久二区 | 春色伊人 | 色就是色网站 | 一级α片免费看刺激高潮视频 | 日韩一区二区三区四区 | 国产性生活 | 丁香花高清视频完整电影 | 亚洲第一精品在线 | 成人免费看aa片 | 国产黄色在线观看 | 777四色| 国产伦精品一区二区三区免费视频 | 性欧美xxxx | 国产一级一级国产 | 色婷婷综合久久久久中文一区二区 | 成人毛片一级 | 老女人综合网 | 午夜资源站 | 影音先锋中文字幕一区 | 男人私人影院 | 偷拍亚洲另类 | 性色av无码久久一区二区三区 | 爱爱三级视频 | 亚洲高清成人 | 可以看污的网站 | 成人依依网 | 中文字幕在线2021 | 激情综合站| 少妇精品导航 | 国产精品网站在线观看 | 国内毛片毛片毛片 | 成人爱爱网站 | 午夜爽爽爽视频 | 成年人午夜免费视频 | 在线视频观看一区二区 | 青青草免费在线观看视频 | 波多野结衣电影免费观看 | 日韩在线精品视频一区二区涩爱 | 欧美国产日韩在线 | 中文字幕一区二区三区四区视频 | 超碰v| 精品无码三级在线观看视频 | 国产sm调教一区二区 | www国产视频 | 不卡视频在线播放 | 欧美人与性囗牲恔配 | 精品人伦一区二区三 | 五月激情五月婷婷 | 深夜福利视频在线 | 无套爆插 | 99久久免费看精品国产一区 | xxxx日本少妇| 欧美午夜在线观看 | 69国产成人精品二区 | 佐佐木明希电影 | 少妇一边呻吟一边说使劲视频 | 久久精品国产精品 | 日韩欧美一卡 | 三级网站| 亚洲av日韩av不卡在线观看 | 日韩黄色短视频 | xxxxhdvideos | 成熟人妻av无码专区 | 中文字幕欧美色图 | 日本在线播放一区 | 涩涩视屏 | 特黄三级| 粉嫩av网站| 色黄网站在线观看 | 亚洲色图25p | 日本一本高清视频 | 大吊av| 中文字幕在线一 | 亚洲啪啪网站 | 亚洲国产精品视频在线 | 毛片天天看 | 高清不卡av | 老司机在线看片 | bl动漫在线观看 | 日吊视频 | 肉番在线观看 | 国产黄色免费观看 | 91精品国产一区二区三区蜜臀 | 亚洲精品码| 国产精品大屁股白浆一区 | 黄色小视频国产 | 亚洲视频自拍偷拍 | 日韩黄色一区二区 | 美女被出白浆 |