一、信號概述
1. 信號概念
信號是一種在軟件層次上對中斷機制的模擬,是一種異步通信方式。信號的產生和處理都由操作系統內核完成,用于在進程之間傳遞信息或通知某些事件的發生。
2. 信號的產生
信號可以通過以下方式產生:
-
按鍵產生:例如用戶按下
Ctrl-C
產生SIGINT
信號,按下Ctrl-\
產生SIGQUIT
信號。 -
系統調用函數產生:例如
kill
、raise
等函數。 -
硬件異常:例如非法指令、除以零等。
-
命令行產生:例如使用
kill
命令向進程發送信號。 -
軟件條件:例如訪問非法內存、管道寫入端關閉等。
3. 信號處理方式
信號可以有以下幾種處理方式:
-
缺省方式:執行系統默認的動作。
-
忽略信號:對信號不做任何處理。
-
捕捉信號:通過自定義函數處理信號。
二、常用信號
信號名 | 含義 | 默認操作 |
---|---|---|
SIGHUP | 用戶終端關閉時產生,發給與終端關聯的會話內的所有進程 | 終止 |
SIGINT | 用戶鍵入Ctrl-C 時產生,發送給當前終端的所有前臺進程 | 終止 |
SIGQUIT | 用戶鍵入Ctrl-\ 時產生,與SIGINT 類似 | 終止 |
SIGILL | 進程企圖執行非法指令時產生 | 終止 |
SIGSEGV | 非法訪問內存時產生,如野指針、緩沖區溢出 | 終止 |
SIGPIPE | 進程往沒有讀端的管道中寫入時產生,代表“管道斷裂” | 終止 |
SIGKILL | 用來結束進程,不能被捕捉和忽略 | 終止 |
SIGSTOP | 暫停進程,不能被捕捉和忽略 | 暫停進程 |
SIGTSTP | 用戶鍵入Ctrl-Z 時產生,用于暫停進程 | 暫停進程 |
SIGCONT | 讓暫停的進程繼續運行 | 繼續運行 |
SIGALRM | 定時器時間到時產生 | 終止 |
SIGUSR1 | 保留給用戶程序使用的信號 | 終止 |
SIGUSR2 | 保留給用戶程序使用的信號 | 終止 |
SIGCHLD | 子進程狀態改變時發給父進程 | 忽略 |
三、信號相關函數
1. kill
函數
函數介紹
#include <sys/types.h> #include <signal.h> ? int kill(pid_t pid, int sig);
-
參數:
-
pid
:目標進程的進程ID。-
> 0
:發送信號給指定進程。 -
= 0
:發送信號給與調用進程處于同一進程組的所有進程。 -
< -1
:發送信號給該進程組的所有進程。 -
= -1
:發送信號給所有有權限發送信號的進程。
-
-
sig
:要發送的信號編號。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:向指定進程發送信號。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? int main() {pid_t pid = 1234; // 假設目標進程ID為1234if (kill(pid, SIGINT) < 0) {perror("kill");return -1;}printf("信號已發送到進程 %d\n", pid);return 0; }
2. raise
函數
函數介紹
#include <signal.h> ? int raise(int sig);
-
參數:
-
sig
:要發送的信號編號。
-
-
返回值:成功時返回0,失敗時返回非0值。
-
作用:向調用進程自身發送信號。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); // 設置SIGINT的處理函數raise(SIGINT); // 向自身發送SIGINT信號while (1) {sleep(1);}return 0; }
3. alarm
函數
函數介紹
#include <unistd.h> ? unsigned int alarm(unsigned int seconds);
-
參數:
-
seconds
:定時時間,單位為秒。如果seconds
為0,則清除之前設置的定時器。
-
-
返回值:返回上次設置的定時器剩余時間(秒)。如果之前沒有設置定時器,則返回0。
-
作用:設置一個定時器,定時結束后向進程發送
SIGALRM
信號。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("定時器信號捕獲到\n"); } ? int main() {signal(SIGALRM, handle); // 設置SIGALRM的處理函數alarm(5); // 設置5秒后發送SIGALRM信號while (1) {sleep(1);}return 0; }
4. ualarm
函數
函數介紹
#include <unistd.h> ? useconds_t ualarm(useconds_t usecs, useconds_t interval);
-
參數:
-
usecs
:第一次定時的時間,單位為微秒。 -
interval
:觸發后的間隔時間,單位為微秒。如果interval
不為0,則定時器會周期性觸發。
-
-
返回值:返回上次設置的定時器剩余時間(微秒)。如果之前沒有設置定時器,則返回0。
-
作用:設置一個微秒級的定時器,定時結束后向進程發送
SIGALRM
信號,并可以設置定時器的間隔時間。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("定時器信號捕獲到\n"); } ? int main() {signal(SIGALRM, handle); // 設置SIGALRM的處理函數ualarm(5000000, 1000000); // 5秒后發送SIGALRM信號,之后每隔1秒發送一次while (1) {sleep(1);}return 0; }
5. setitimer
函數
函數介紹
#include <sys/time.h> ? int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
-
參數:
-
which
:定時器類型。-
ITIMER_REAL
:以實際時間計時,發送SIGALRM
信號。 -
ITIMER_VIRTUAL
:以用戶態運行時間計時,發送SIGVTALRM
信號。 -
ITIMER_PROF
:以用戶態和內核態運行時間計時,發送SIGPROF
信號。
-
-
new_value
:指向新的定時器值的結構體。 -
old_value
:指向存儲舊的定時器值的結構體(可選)。
-
-
結構體
itimerval
:-
struct timeval it_interval
:定時器的間隔時間。 -
struct timeval it_value
:定時器的初始時間。
-
-
結構體
timeval
:-
time_t tv_sec
:秒。 -
suseconds_t tv_usec
:微秒。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:設置一個間隔定時器。
示例代碼
#include <stdio.h> #include <signal.h> #include <sys/time.h> #include <unistd.h> ? void handle(int sig) {printf("定時器信號捕獲到\n"); } ? int main() {struct itimerval timer;timer.it_interval.tv_sec = 1;timer.it_interval.tv_usec = 0;timer.it_value.tv_sec = 5;timer.it_value.tv_usec = 0; ?signal(SIGALRM, handle); // 設置SIGALRM的處理函數setitimer(ITIMER_REAL, &timer, NULL); // 設置定時器while (1) {sleep(1);}return 0; }
6. signal
函數
函數介紹
#include <signal.h> ? typedef void (*sighandler_t)(int); ? sighandler_t signal(int signum, sighandler_t handler);
-
參數:
-
signum
:要設置的信號編號。 -
handler
:信號處理函數。-
SIG_DFL
:恢復為默認處理方式。 -
SIG_IGN
:忽略信號。 -
其他:自定義處理函數。
-
-
-
返回值:成功時返回之前的信號處理函數,失敗時返回
SIG_ERR
。 -
作用:設置信號處理方式。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); // 設置SIGINT的處理函數while (1) {sleep(1);}return 0; }
7. sigaction
函數
函數介紹
#include <signal.h> ? int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
-
參數:
-
signum
:要設置的信號編號。 -
act
:指向新的信號處理方式的結構體。 -
oldact
:指向存儲舊的信號處理方式的結構體(可選)。
-
-
結構體
sigaction
:-
void (*sa_handler)(int)
:信號處理函數。 -
void (*sa_sigaction)(int, siginfo_t *, void *)
:支持傳遞額外信息的信號處理函數。 -
sigset_t sa_mask
:在信號處理函數執行期間需要屏蔽的信號集。 -
int sa_flags
:信號處理標志。-
SA_SIGINFO
:使用sa_sigaction
成員而不是sa_handler
作為信號處理函數。 -
SA_RESTART
:使被信號打斷的系統調用自動重新發起。 -
SA_RESETHAND
:信號處理之后重新設置為默認的處理方式。 -
SA_NODEFER
:使對信號的屏蔽無效,即在信號處理函數執行期間仍能發出這個信號。
-
-
void (*sa_restorer)(void)
:已廢棄。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:設置信號處理方式,功能比
signal
更強大。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {struct sigaction act;act.sa_handler = handle;sigemptyset(&act.sa_mask);act.sa_flags = 0; ?sigaction(SIGINT, &act, NULL); // 設置SIGINT的處理方式while (1) {sleep(1);}return 0; }
四、信號集操作函數
1. sigemptyset
函數
函數介紹
#include <signal.h> ? int sigemptyset(sigset_t *set);
-
參數:
-
set
:指向信號集的指針。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:清空信號集。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set;sigemptyset(&set); // 清空信號集return 0; }
2. sigfillset
函數
函數介紹
#include <signal.h> ? int sigfillset(sigset_t *set);
-
參數:
-
set
:指向信號集的指針。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:將信號集中的所有信號都設置為1。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set;sigfillset(&set); // 填充信號集return 0; }
3. sigaddset
函數
函數介紹
#include <signal.h> ? int sigaddset(sigset_t *set, int signum);
-
參數:
-
set
:指向信號集的指針。 -
signum
:要添加到信號集中的信號編號。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:將指定信號添加到信號集中。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set;sigemptyset(&set);sigaddset(&set, SIGINT); // 添加SIGINT到信號集return 0; }
4. sigdelset
函數
函數介紹
#include <signal.h> ? int sigdelset(sigset_t *set, int signum);
-
參數:
-
set
:指向信號集的指針。 -
signum
:要從信號集中移除的信號編號。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:從信號集中移除指定的信號。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set;sigfillset(&set);sigdelset(&set, SIGINT); // 從信號集中移除SIGINTreturn 0; }
5. sigismember
函數
函數介紹
#include <signal.h> ? int sigismember(const sigset_t *set, int signum);
-
參數:
-
set
:指向信號集的指針。 -
signum
:要檢查的信號編號。
-
-
返回值:
-
如果信號在信號集中,返回1。
-
如果信號不在信號集中,返回0。
-
如果出錯,返回-1。
-
-
作用:檢查指定信號是否在信號集中。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set;sigemptyset(&set);sigaddset(&set, SIGINT); ?if (sigismember(&set, SIGINT)) {printf("SIGINT在信號集中。\n");} else {printf("SIGINT不在信號集中。\n");} ?return 0; }
五、信號的阻塞與掛起
1. sigprocmask
函數
函數介紹
#include <signal.h> ? int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
-
參數:
-
how
:指定如何修改當前信號屏蔽字。-
SIG_BLOCK
:將set
中的信號添加到當前信號屏蔽字中。 -
SIG_UNBLOCK
:從當前信號屏蔽字中移除set
中的信號。 -
SIG_SETMASK
:將當前信號屏蔽字設置為set
中的信號。
-
-
set
:指向新的信號屏蔽集的指針。 -
oset
:指向存儲舊的信號屏蔽集的指針(可選)。
-
-
返回值:成功時返回0,失敗時返回-1。
-
作用:設置或獲取進程的信號屏蔽字。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {sigset_t set; ?sigemptyset(&set);sigaddset(&set, SIGINT); ?signal(SIGINT, handle); ?sigprocmask(SIG_BLOCK, &set, NULL); // 阻塞SIGINT信號sleep(5); // 在這5秒內,SIGINT信號會被阻塞 ?sigprocmask(SIG_UNBLOCK, &set, NULL); // 解除SIGINT信號的阻塞 ?while (1) {sleep(1);}return 0; }
2. pause
函數
函數介紹
#include <unistd.h> ? int pause(void);
-
返回值:總是返回-1,并設置
errno
為EINTR
。 -
作用:使進程掛起,直到接收到信號為止。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); ?printf("進程已掛起。按Ctrl-C繼續。\n");pause(); // 掛起進程printf("進程已恢復。\n");return 0; }
3. sigsuspend
函數
函數介紹
#include <signal.h> ? int sigsuspend(const sigset_t *sigmask);
-
參數:
-
sigmask
:指向信號屏蔽集的指針。
-
-
返回值:總是返回-1,并設置
errno
為EINTR
。 -
作用:將進程的信號屏蔽字設置為
sigmask
,然后掛起進程,直到接收到信號為止。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {sigset_t set; ?sigemptyset(&set);sigaddset(&set, SIGINT); ?signal(SIGINT, handle); ?printf("進程已掛起。按Ctrl-C繼續。\n");sigsuspend(&set); // 掛起進程printf("進程已恢復。\n");return 0; }
六、使用SIGCHLD
信號回收子進程
1. SIGCHLD
信號
SIGCHLD
信號在以下情況下產生:
-
子進程終止。
-
子進程接收到
SIGSTOP
信號而暫停。 -
子進程從暫停狀態被喚醒。
父進程可以通過捕捉SIGCHLD
信號來回收子進程,避免產生僵尸進程。
示例代碼
#include <stdio.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> ? void handle(int sig) {wait(NULL); // 回收子進程printf("子進程已終止。信號 %d 收到。\n", sig); } ? int main() {pid_t pid; ?struct sigaction act;act.sa_handler = handle;act.sa_flags = 0;sigemptyset(&act.sa_mask);sigaction(SIGCHLD, &act, NULL); // 設置SIGCHLD的處理函數 ?pid = fork();if (pid > 0) {// 父進程while (1) {printf("父進程正在運行。PID: %d\n", getpid());sleep(1);}} else if (pid == 0) {// 子進程printf("子進程正在運行。PID: %d\n", getpid());sleep(5);exit(0);} ?return 0; }
七、定時器的實現
1. alarm
函數
alarm
函數用于設置一個定時器,當定時時間到達時,系統會向進程發送SIGALRM
信號。
函數原型:
#include <unistd.h> ? unsigned int alarm(unsigned int seconds);
參數:
-
seconds
:定時時間,單位為秒。如果seconds
為0,則清除之前設置的定時器。
返回值:
-
返回上次設置的定時器剩余時間(秒)。如果之前沒有設置定時器,則返回0。
示例代碼:
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle_sigalrm(int sig) {printf("定時器信號捕獲到\n");alarm(1); // 重新設置定時器,實現周期性觸發 } ? int main() {signal(SIGALRM, handle_sigalrm); ?alarm(1); // 設置1秒后觸發定時器 ?printf("等待定時器信號...\n");while (1) {pause();} ?return 0; }
2. ualarm
函數
ualarm
函數用于設置一個微秒級的定時器,當定時時間到達時,系統會向進程發送SIGALRM
信號。它可以設置一次性定時器或周期性定時器。
函數原型:
#include <unistd.h> ? useconds_t ualarm(useconds_t usecs, useconds_t interval);
參數:
-
usecs
:首次觸發的時間,單位為微秒。 -
interval
:觸發后的間隔時間,單位為微秒。如果interval
不為0,則定時器會周期性觸發。
返回值:
-
返回上次設置的定時器剩余時間(微秒)。如果之前沒有設置定時器,則返回0。
示例代碼:
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle_sigalrm(int sig) {printf("定時器信號捕獲到\n"); } ? int main() {signal(SIGALRM, handle_sigalrm); ?ualarm(5000000, 1000000); // 5秒后觸發,之后每隔1秒觸發一次 ?printf("等待定時器信號...\n");while (1) {pause();} ?return 0; }
3. setitimer
函數
setitimer
函數用于設置一個間隔定時器,可以指定定時器的類型,并在定時時間到達時發送相應的信號。
函數原型:
#include <sys/time.h> ? int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
參數:
-
which
:定時器類型,可選值為:-
ITIMER_REAL
:基于實際時間的定時器,觸發時發送SIGALRM
信號。 -
ITIMER_VIRTUAL
:基于用戶態運行時間的定時器,觸發時發送SIGVTALRM
信號。 -
ITIMER_PROF
:基于用戶態和內核態運行時間的定時器,觸發時發送SIGPROF
信號。
-
-
new_value
:指向新的定時器設置的指針。 -
old_value
:指向存儲舊的定時器設置的指針(可選)。
結構體itimerval
:
struct itimerval {struct timeval it_interval; // 定時器的間隔時間struct timeval it_value; ? ?// 定時器的初始時間 };
結構體timeval
:
struct timeval {long tv_sec; ? ? ? ? // 秒long tv_usec; ? ? ? ?// 微秒 };
返回值:
-
成功時返回0,失敗時返回-1。
示例代碼:
#include <stdio.h> #include <signal.h> #include <sys/time.h> #include <unistd.h> ? void handle_sigalrm(int sig) {printf("定時器信號捕獲到\n");struct itimerval timer;timer.it_interval.tv_sec = 1;timer.it_interval.tv_usec = 0;timer.it_value.tv_sec = 1;timer.it_value.tv_usec = 0;setitimer(ITIMER_REAL, &timer, NULL); // 重新設置定時器 } ? int main() {struct itimerval timer; ?signal(SIGALRM, handle_sigalrm); ?timer.it_interval.tv_sec = 1;timer.it_interval.tv_usec = 0;timer.it_value.tv_sec = 1;timer.it_value.tv_usec = 0;setitimer(ITIMER_REAL, &timer, NULL); ?printf("等待定時器信號...\n");while (1) {pause();} ?return 0; }
八、信號的捕捉與處理
1. 信號捕捉過程
信號捕捉的步驟如下:
-
定義信號處理函數,該函數在信號到達時被調用。
-
使用
signal
或sigaction
函數將信號與處理函數關聯起來。
2. signal
函數
signal
函數用于設置信號的處理方式。
函數原型:
#include <signal.h> ? typedef void (*sighandler_t)(int); ? sighandler_t signal(int signum, sighandler_t handler);
參數:
-
signum
:要設置處理方式的信號編號。 -
handler
:信號處理函數,或者SIG_DFL
(恢復默認處理)、SIG_IGN
(忽略信號)。
返回值:
-
返回之前的信號處理函數,如果設置失敗則返回
SIG_ERR
。
示例代碼:
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle_sigint(int sig) {printf("SIGINT信號捕獲到\n"); } ? int main() {signal(SIGINT, handle_sigint); ?printf("進程正在運行。按Ctrl+C發送SIGINT。\n");while (1) {sleep(1);} ?return 0; }
3. sigaction
函數
sigaction
函數提供了更靈活的信號處理設置,推薦使用。
函數原型:
#include <signal.h> ? int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
參數:
-
signum
:要設置處理方式的信號編號。 -
act
:指向新的信號處理動作的指針。 -
oldact
:指向存儲舊的信號處理動作的指針(可選)。
結構體sigaction
:
struct sigaction {void (*sa_handler)(int); ? ? ? ? ?// 信號處理函數void (*sa_sigaction)(int, siginfo_t *, void *); // 帶額外信息的處理函數sigset_t sa_mask; ? ? ? ? ? ? ? ? // 處理信號時屏蔽的信號集int sa_flags; ? ? ? ? ? ? ? ? ? ? // 信號處理標志void (*sa_restorer)(void); ? ? ? ?// 已廢棄 };
常用sa_flags
標志:
-
SA_SIGINFO
:使用sa_sigaction
而不是sa_handler
。 -
SA_RESTART
:被信號中斷的系統調用會自動重新發起。 -
SA_NODEFER
:在信號處理函數執行期間,不對該信號進行屏蔽。
示例代碼:
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle_sigint(int sig) {printf("SIGINT信號捕獲到\n"); } ? int main() {struct sigaction act; ?act.sa_handler = handle_sigint;sigemptyset(&act.sa_mask);act.sa_flags = 0; ?sigaction(SIGINT, &act, NULL); ?printf("進程正在運行。按Ctrl+C發送SIGINT。\n");while (1) {sleep(1);} ?return 0; }
九、信號的阻塞與掛起
1. 信號的阻塞
信號的阻塞是指阻止信號被處理,但信號仍然可以產生。阻塞信號不會被立即處理,而是等到解除阻塞后才處理。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {sigset_t set; ?sigemptyset(&set);sigaddset(&set, SIGINT); ?signal(SIGINT, handle); ?sigprocmask(SIG_BLOCK, &set, NULL); // 阻塞SIGINT信號sleep(5); // 在這5秒內,SIGINT信號會被阻塞 ?sigprocmask(SIG_UNBLOCK, &set, NULL); // 解除SIGINT信號的阻塞 ?while (1) {sleep(1);}return 0; }
2. pause
函數
pause
函數使進程掛起,直到接收到信號為止。如果信號的處理動作是終止進程,則pause
函數不會返回;如果信號的處理動作是忽略,則進程繼續掛起;如果信號的處理動作是捕捉,則調用完信號處理函數后,pause
函數返回-1。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); ?printf("進程已掛起。按Ctrl-C繼續。\n");pause(); // 掛起進程 ?printf("進程已恢復。\n");return 0; }
3. sigsuspend
函數
sigsuspend
函數將進程的信號屏蔽字設置為指定的信號集,然后掛起進程,直到接收到信號為止。它通常用于在信號處理函數中臨時更改信號屏蔽字。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {sigset_t set; ?sigemptyset(&set);sigaddset(&set, SIGINT); ?signal(SIGINT, handle); ?printf("進程已掛起。按Ctrl-C繼續。\n");sigsuspend(&set); // 掛起進程 ?printf("進程已恢復。\n");return 0; }
十、信號集操作
1. 信號集操作函數
信號集操作函數用于管理信號集,可以清空、填充、添加、刪除和檢查信號集中的信號。
示例代碼
#include <stdio.h> #include <signal.h> ? int main() {sigset_t set; ?sigemptyset(&set); // 清空信號集sigaddset(&set, SIGINT); // 添加SIGINT到信號集sigaddset(&set, SIGQUIT); // 添加SIGQUIT到信號集 ?if (sigismember(&set, SIGINT)) {printf("SIGINT在信號集中。\n");} else {printf("SIGINT不在信號集中。\n");} ?if (sigismember(&set, SIGQUIT)) {printf("SIGQUIT在信號集中。\n");} else {printf("SIGQUIT不在信號集中。\n");} ?sigdelset(&set, SIGINT); // 從信號集中刪除SIGINT ?if (sigismember(&set, SIGINT)) {printf("SIGINT在信號集中。\n");} else {printf("SIGINT不在信號集中。\n");} ?return 0; }
十一、信號的忽略與默認處理
1. 忽略信號
可以使用signal
函數將信號處理方式設置為SIG_IGN
,從而忽略指定的信號。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? int main() {signal(SIGINT, SIG_IGN); // 忽略SIGINT信號 ?printf("SIGINT信號被忽略。按Ctrl+C測試。\n");while (1) {sleep(1);} ?return 0; }
2. 恢復默認處理
可以使用signal
函數將信號處理方式設置為SIG_DFL
,從而恢復系統的默認處理方式。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); // 設置SIGINT的處理函數sleep(5); ?signal(SIGINT, SIG_DFL); // 恢復SIGINT的默認處理方式 ?printf("SIGINT信號恢復為默認處理。按Ctrl+C測試。\n");while (1) {sleep(1);} ?return 0; }
十二、信號在進程間通信中的應用
1. 使用kill
命令發送信號
可以在命令行使用kill
命令向指定進程發送信號。
示例代碼
# 向進程ID為1234的進程發送SIGINT信號 kill -SIGINT 1234
2. 使用raise
函數發送信號給自己
可以使用raise
函數向自身發送信號。
示例代碼
#include <stdio.h> #include <signal.h> #include <unistd.h> ? void handle(int sig) {printf("捕獲到信號 %d\n", sig); } ? int main() {signal(SIGINT, handle); // 設置SIGINT的處理函數raise(SIGINT); // 向自身發送SIGINT信號while (1) {sleep(1);}return 0; }