8、linux c 信號機制

一、信號概述

1. 信號概念

信號是一種在軟件層次上對中斷機制的模擬,是一種異步通信方式。信號的產生和處理都由操作系統內核完成,用于在進程之間傳遞信息或通知某些事件的發生。

2. 信號的產生

信號可以通過以下方式產生:

  1. 按鍵產生:例如用戶按下Ctrl-C產生SIGINT信號,按下Ctrl-\產生SIGQUIT信號。

  2. 系統調用函數產生:例如killraise等函數。

  3. 硬件異常:例如非法指令、除以零等。

  4. 命令行產生:例如使用kill命令向進程發送信號。

  5. 軟件條件:例如訪問非法內存、管道寫入端關閉等。

3. 信號處理方式

信號可以有以下幾種處理方式:

  1. 缺省方式:執行系統默認的動作。

  2. 忽略信號:對信號不做任何處理。

  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,并設置errnoEINTR

  • 作用:使進程掛起,直到接收到信號為止。

示例代碼
#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,并設置errnoEINTR

  • 作用:將進程的信號屏蔽字設置為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信號在以下情況下產生:

  1. 子進程終止。

  2. 子進程接收到SIGSTOP信號而暫停。

  3. 子進程從暫停狀態被喚醒。

父進程可以通過捕捉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. 信號捕捉過程

信號捕捉的步驟如下:

  1. 定義信號處理函數,該函數在信號到達時被調用。

  2. 使用signalsigaction函數將信號與處理函數關聯起來。

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75045.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75045.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75045.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CSP-J 2019 入門級 第一輪(初賽) 完善程序(2)

【題目】 CSP-J 2019 入門級 第一輪&#xff08;初賽&#xff09; 完善程序&#xff08;2&#xff09; &#xff08;計數排序&#xff09;計數排序是一個廣泛使用的排序方法。下面的程序使用雙關鍵字計數排序&#xff0c;將n對10000 以內的整數&#xff0c;從小到大排序。 例如…

Vue3 項目通過 docxtemplater 插件動態渲染 .docx 文檔(帶圖片)預覽,并導出

Vue3 項目通過 docxtemplater 插件動態渲染 .docx 文檔&#xff08;帶圖片&#xff09;預覽&#xff0c;并導出 預覽安裝插件示例代碼項目目錄結構截圖實際效果截圖 動態渲染 .docx 文檔&#xff08;帶圖片&#xff09;&#xff0c;預覽、導出安裝插件docx 模板文件內容完整代碼…

養老更安心!智紳科技“智慧”養老系統,智在何處?

在老齡化趨勢不斷加劇的當下&#xff0c;養老問題成為全社會關注的焦點。 人們對于養老服務的需求日益增長&#xff0c;不僅期望能夠得到基本的生活照料&#xff0c;更渴望在安全、舒適、便捷的環境中安享晚年。 智紳科技的“智慧”養老系統應運而生&#xff0c;憑借其獨特的…

MySQL 當中的鎖

MySQL 當中的鎖 文章目錄 MySQL 當中的鎖MySQL 中有哪些主要類型的鎖&#xff1f;請簡要說明MySQL 的全局鎖有什么用&#xff1f;MySQL 的表級鎖有哪些&#xff1f;作用是什么&#xff1f;元數據鎖&#xff08;MetaData Lock&#xff0c;MDL&#xff09;意向鎖&#xff08;Inte…

vue前端代碼作業——待辦事項

美化樣式示意圖&#xff1a; 后端IDEA代碼示意圖&#xff1a; 代碼解釋&#xff1a; 1. isAllChecked 計算屬性的作用 isAllChecked 用于實現 “全選 / 全不選” 功能&#xff0c;它是一個 雙向綁定 的計算屬性&#xff08;因為 v-model 需要同時支持讀取和設置值&#xff09…

Oracle數據庫數據編程SQL<3.1 PL/SQL 匿名塊 及 流程控制中的條件判斷、循環、異常處理和隨機函數應用>

PL/SQL部分 在SQL的基礎上增加了一些過程化的控制語句。 過程化控制語句包括&#xff1a;類型定義、判斷、循環、游標、異常處理&#xff08;例外處理&#xff09; 目錄 PL/SQL匿名塊 一、匿名塊基本結構 1、匿名塊由三個部分組成&#xff1a; 2、注意事項&#xff1a; …

DeepSeek詳解:探索下一代語言模型

文章目錄 前言一、什么是DeepSeek二、DeepSeek核心技術2.1 Transformer架構2.1.1 自注意力機制 (Self-Attention Mechanism)(a) 核心思想(b) 計算過程(c) 代碼實現 2.1.2 多頭注意力 (Multi-Head Attention)(a) 核心思想(b) 工作原理(c) 數學描述(d) 代碼實現 2.1.3 位置編碼 (…

Git Reset 命令詳解與實用示例

文章目錄 Git Reset 命令詳解與實用示例git reset 主要選項git reset 示例1. 撤銷最近一次提交&#xff08;但保留更改&#xff09;2. 撤銷最近一次提交&#xff0c;并清除暫存區3. 徹底撤銷提交&#xff0c;并丟棄所有更改4. 回退到特定的提交5. 取消暫存的文件 git reset 與 …

前端知識點---事件監聽器里面的e.target跟this的區別,e.target在事件委托中的好處

文章目錄 ? 相同點? 不同點? 總結區別e.target與事件委托之間的關系 在事件監聽器中&#xff0c;e.target 和 this 有時是一樣的&#xff0c;但它們并不完全相同。 ? 相同點 當事件直接綁定到元素時&#xff1a; e.target 和 this 通常指向相同的元素&#xff0c;即事件綁…

Elasticsearch 完全指南

1. Elasticsearch基礎知識 1.1 什么是Elasticsearch Elasticsearch是一個基于Lucene的分布式、RESTful風格的搜索和數據分析引擎。它是一個開源的、高擴展的、分布式的全文搜索引擎,可以近乎實時地存儲、檢索數據。 Elasticsearch不僅僅是一個全文搜索引擎,它還可以用于以…

Python 3 與 MySQL 數據庫連接:mysql-connector 模塊詳解

Python 3 與 MySQL 數據庫連接&#xff1a;mysql-connector 模塊詳解 概述 在Python 3中&#xff0c;與MySQL數據庫進行交互是一個常見的需求。mysql-connector是一個流行的Python模塊&#xff0c;它提供了與MySQL數據庫連接和交互的接口。本文將詳細介紹mysql-connector模塊…

SQL:CASE WHEN使用詳解

文章目錄 1. 數據轉換與映射2. 動態條件篩選3. 多條件分組統計4. 數據排名與分級5. 處理空值與默認值6. 動態排序 CASE WHEN 語句在 SQL 中是一個非常強大且靈活的工具&#xff0c;除了常規的條件判斷外&#xff0c;還有很多巧妙的用法&#xff0c;以下為你詳細總結&#xff1a…

【字符設備驅動開發–IMX6ULL】(二)Linux 設備號

【字符設備驅動開發–IMX6ULL】&#xff08;二&#xff09;Linux 設備號 文章目錄 【字符設備驅動開發–IMX6ULL】&#xff08;二&#xff09;Linux 設備號1 設備號的組成2.設備號的分配 1 設備號的組成 為了方便管理&#xff0c;Linux 中每個設備都有一個設備號&#xff0c;設…

【字符設備驅動開發–IMX6ULL】(一)簡介

【字符設備驅動開發–IMX6ULL】&#xff08;一&#xff09;簡介 一、Linux驅動與裸機開發區別 1.裸機驅動開發回顧 ? 1、底層&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了庫。 spi.c&#xff1a;主機驅動&#xff08;換成任何一個設備之后只需要調用此文件里面的…

YOLOv8+ Deepsort+Pyqt5車速檢測系統

該系統通過YOLOv8進行高效的目標檢測與分割&#xff0c;結合DeepSORT算法完成目標的實時跟蹤&#xff0c;并利用GPU加速技術提升處理速度。系統支持模塊化設計&#xff0c;可導入其他權重文件以適應不同場景需求&#xff0c;同時提供自定義配置選項&#xff0c;如顯示標簽和保存…

藍橋杯嵌入式學習筆記

用博客來記錄一下參加藍橋杯嵌入式第十六屆省賽的學習經歷 工具環境準備cubemx配置外部高速時鐘使能設置串口時鐘配置項目配置 keil配置燒錄方式注意代碼規范頭文件配置 模塊ledcubemx配置keil代碼實現點亮一只燈實現具體操作的燈&#xff0c;以及點亮還是熄滅 按鍵cubemx配置k…

ARCGIS PRO SDK VB2022 圖層要素類類型判斷

arcgis pro 常見要素類類型有以下幾種&#xff1a; FeatureLayer ——要素圖層&#xff08;矢量數據&#xff09; RasterLayer ——柵格圖層 MapImageLayer ——地圖圖像圖層 VectorTileLayer ——矢量切片圖層 SceneLayer …

【hadoop】遠程調試環境

根據上一節&#xff0c;我們已經安裝完成hadoop偽分布式環境 hadoop集群環境配置_jdk1.8 441-CSDN博客 還沒安裝的小伙伴可以看看這個帖子 這一節我們要實現使用vscode進行遠程連接&#xff0c;并且完成java配置與測試 目錄 vscode 配置遠程 安裝java插件 新建java項目 …

Java版Manus實現來了,Spring AI Alibaba發布開源OpenManus實現

此次官方發布的 Spring AI Alibaba OpenManus 實現&#xff0c;包含完整的多智能體任務規劃、思考與執行流程&#xff0c;可以讓開發者體驗 Java 版本的多智能體效果。它能夠根據用戶的問題進行分析&#xff0c;操作瀏覽器&#xff0c;執行代碼等來完成復雜任務等。 項目源碼及…

【Linux網絡與網絡編程】02.初識Socket編程

1. 數據傳輸的目的 前一篇文章中我們講解了網絡傳輸的流程&#xff0c;那么網絡傳輸的目的是什么呢&#xff1f;難道我們只是將數據從一臺主機傳輸到另一臺主機嗎&#xff1f; 當然不是的&#xff01;因為數據是給人用的。比如&#xff1a;聊天是人在聊天&#xff0c;下載是人…