目錄
0. 信號(hào)概述
1. 產(chǎn)生信號(hào)的方式:
1.1 當(dāng)用戶按某些終端鍵時(shí),將產(chǎn)生信號(hào)。
1.2 硬件異常將產(chǎn)生信號(hào)。
1.3 軟件異常將產(chǎn)生信號(hào)。
1.4 調(diào)用kill函數(shù)將發(fā)送信號(hào)。
1.5 運(yùn)行kill命令將發(fā)送信號(hào)。
2. 信號(hào)的默認(rèn)(缺?。┨幚矸绞?/p>
2.1 終止進(jìn)程:
2.2 缺省出來:
2.3 停止進(jìn)程:
2.4 讓停止的進(jìn)程恢復(fù)運(yùn)行:
3. 進(jìn)程收到信號(hào)后的處理方式
3.1 執(zhí)行系統(tǒng)默認(rèn)動(dòng)作
3.2 忽略此信號(hào)
3.3 執(zhí)行自定義信號(hào)處理函數(shù)
4. 常見的信號(hào):?
5. 信號(hào)的基本操作
5.1 kill函數(shù)
5.2 alarm函數(shù)
5.3 setitimer函數(shù)(定時(shí)器)?
?5.4 raise函數(shù)
5.5 abort函數(shù)
5.6 pause函數(shù)
5.7 signal函數(shù)
6. 信號(hào)集
6.1 信號(hào)集概述
6.2 信號(hào)集數(shù)據(jù)類型
6.3 定義路徑:
?6.4 信號(hào)集相關(guān)的操作主要有以下幾個(gè)函數(shù):
7. 信號(hào)阻塞集(屏蔽集、掩碼)
7.1 sigprocmask函數(shù)
7.2 sigpending函數(shù)
總結(jié):
0. 信號(hào)概述
????????信號(hào)是軟件中斷,它是在軟件層次上對(duì)中斷機(jī)制的一種模擬。
????????信號(hào)可以導(dǎo)致一個(gè)正在運(yùn)行的進(jìn)程被另一個(gè)正在運(yùn)行的異步進(jìn)程中斷,轉(zhuǎn)而處理某一個(gè)突發(fā)事件。
????????信號(hào)是一種異步通信方式。
????????進(jìn)程不必等待信號(hào)的到達(dá),進(jìn)程也不知道信號(hào)什么時(shí)候到達(dá)。
????????信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核空間進(jìn)程的交互,內(nèi)核進(jìn)程可以利用它來通知 用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。
????????每個(gè)信號(hào)的名字都以字符 SIG 開頭。
????????每個(gè)信號(hào)和一個(gè)數(shù)字編碼相對(duì)應(yīng),在頭文件 signum.h 中,這些信號(hào)都被定義為正整數(shù)。
信號(hào)名定義路徑: /usr/include/x86_64-linux-gnu/bits/signum.h (ubuntu12.04)
在 Linux 下,要想查看這些信號(hào)和編碼的對(duì)應(yīng)關(guān)系,可使用命令:kill -l
????????信號(hào)是由當(dāng)前系統(tǒng)已經(jīng)定義好的一些標(biāo)識(shí),每一個(gè)標(biāo)識(shí)都會(huì)在特定的場(chǎng)合使用。并且都會(huì)對(duì)進(jìn)程有一定的影響,當(dāng)信號(hào)產(chǎn)生時(shí),會(huì)讓當(dāng)前信號(hào)做出相應(yīng)的操作。這些信號(hào)都是已經(jīng)定義好的,我們不能自己在去創(chuàng)造,直接使用這些就可以了。
1. 產(chǎn)生信號(hào)的方式:
1.1 當(dāng)用戶按某些終端鍵時(shí),將產(chǎn)生信號(hào)。
例如:終端上按“Ctrl+c”組合鍵通常產(chǎn)生中斷信號(hào) SIGINT
???????????終端上按"Ctrl+\"鍵通常產(chǎn) 生中斷信號(hào) SIGQUIT
? ? ? ? ? ?終端上按"Ctrl+z"鍵通常產(chǎn)生中斷信號(hào) SIGSTOP。
1.2 硬件異常將產(chǎn)生信號(hào)。
????????除數(shù)為 0,無效的內(nèi)存訪問等。這些情況通常由硬件檢測(cè)到,并通知內(nèi)核,然后內(nèi) 核產(chǎn)生適當(dāng)?shù)男盘?hào)發(fā)送給相應(yīng)的進(jìn)程。
1.3 軟件異常將產(chǎn)生信號(hào)。
????????當(dāng)檢測(cè)到某種軟件條件已發(fā)生,并將其通知有關(guān)進(jìn)程時(shí),產(chǎn)生信號(hào)。
1.4 調(diào)用kill函數(shù)將發(fā)送信號(hào)。
????????注意:接收信號(hào)進(jìn)程和發(fā)送信號(hào)進(jìn)程的所有者必須相同,或發(fā)送信號(hào)進(jìn)程的 所有者必須是超級(jí)用戶。
1.5 運(yùn)行kill命令將發(fā)送信號(hào)。
????????此程序?qū)嶋H上是使用 kill函數(shù)來發(fā)送信號(hào)。也常用此命令終止一個(gè)失控的后臺(tái)進(jìn)程。
2. 信號(hào)的默認(rèn)(缺?。┨幚矸绞?/h3>
當(dāng)進(jìn)程中產(chǎn)生了一個(gè)信號(hào),就會(huì)讓當(dāng)前進(jìn)程做出一定的反應(yīng)。
默認(rèn)處理進(jìn)程的方式如下:
2.1 終止進(jìn)程:
????????當(dāng)信號(hào)產(chǎn)生后,當(dāng)前進(jìn)程就會(huì)立即結(jié)束。
2.2 缺省出來:
????????當(dāng)信號(hào)產(chǎn)生后,當(dāng)前進(jìn)程不做任何處理。
2.3 停止進(jìn)程:
????????當(dāng)信號(hào)產(chǎn)生后,使得當(dāng)前進(jìn)程停止。
2.4 讓停止的進(jìn)程恢復(fù)運(yùn)行:
????????當(dāng)信號(hào)產(chǎn)生后,停止的進(jìn)程會(huì)恢復(fù)執(zhí)行(后臺(tái)進(jìn)程)。
注意:每一個(gè)信號(hào)只有一個(gè)默認(rèn)的處理方式。
3. 進(jìn)程收到信號(hào)后的處理方式
3.1 執(zhí)行系統(tǒng)默認(rèn)動(dòng)作
????????對(duì)大多數(shù)信號(hào)來說,系統(tǒng)默認(rèn)動(dòng)作是用來終止該進(jìn)程。
3.2 忽略此信號(hào)
????????接收到此信號(hào)后沒有任何動(dòng)作。
3.3 執(zhí)行自定義信號(hào)處理函數(shù)
????????用用戶定義的信號(hào)處理函數(shù)處理該信號(hào)。
注意:SIGKILL和SIGSTOP這兩個(gè)信號(hào)只能以默認(rèn)的處理方式執(zhí)行,不能忽略,也不能自定義。
4. 常見的信號(hào):?
信號(hào) | 值 | 性質(zhì) | 默認(rèn)處理方式 |
SIGKILL | 9 | 當(dāng)產(chǎn)生這個(gè)信號(hào)后,當(dāng)前進(jìn)程會(huì)退出,不能被缺省和捕捉 | 退出進(jìn)程 |
SIGSTOP | 19 | 當(dāng)產(chǎn)生這個(gè)信號(hào)后,當(dāng)前進(jìn)程會(huì)停止,不能缺省和捕捉 | 停止進(jìn)程 |
SIGINT | 2 | 鍵盤輸入ctrl+c時(shí)產(chǎn)生信號(hào) | 退出進(jìn)程 |
SIGQUIT | 3 | 鍵盤輸入ctrl+\時(shí)產(chǎn)生信號(hào) | 退出進(jìn)程 |
SIGSTP | 20 | 鍵盤輸入ctrl+z時(shí)產(chǎn)生信號(hào) | 停止進(jìn)程 |
SIGCONT | 18 | 當(dāng)產(chǎn)生當(dāng)前信號(hào)后,當(dāng)前停止的進(jìn)程會(huì)恢復(fù)運(yùn)行 | 停止的進(jìn)程恢復(fù)運(yùn)行 |
SIGALRM | 14 | 當(dāng)調(diào)用alarm函數(shù)設(shè)置的時(shí)間到達(dá)時(shí)會(huì)產(chǎn)生當(dāng)前信號(hào) | 退出進(jìn)程 |
SIGPIPE | 13 | 當(dāng)管道破裂時(shí),會(huì)產(chǎn)生當(dāng)前信號(hào) | 退出進(jìn)程 |
SIGABRT | 6 | 當(dāng)調(diào)用abort函數(shù)時(shí)會(huì)產(chǎn)生當(dāng)前信號(hào) | 退出進(jìn)程 |
SIGCHLD | 17 | 當(dāng)使用fork創(chuàng)建一個(gè)子進(jìn)程時(shí),如果子進(jìn)程狀態(tài)改變(退出),會(huì)產(chǎn)生當(dāng)前信號(hào) | 缺省 |
SIGUSR1 | 10 | 用戶自定義信號(hào),不會(huì)自動(dòng)產(chǎn)生,只能使用kill函數(shù)或命令給指定的進(jìn)程發(fā)送當(dāng)前信號(hào) | 缺省 |
SIGUSR2 | 12 | 用戶自定義信號(hào),不會(huì)自動(dòng)產(chǎn)生,只能使用kill函數(shù)或命令給指定的進(jìn)程發(fā)送當(dāng)前信號(hào) | 缺省 |
5. 信號(hào)的基本操作
5.1 kill函數(shù)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signum);
功能:
? ? 給指定進(jìn)程發(fā)送信號(hào)。
參數(shù):
? ? pid:
? ? ? ? pid 的取值有 4 種情況:?
? ? ? ? pid>0: 將信號(hào)傳送給進(jìn)程 ID 為 pid 的進(jìn)程。
? ? ? ? pid=0: 將信號(hào)傳送給當(dāng)前進(jìn)程所在進(jìn)程組中的所有進(jìn)程。
? ? ? ? pid=-1: 將信號(hào)傳送給系統(tǒng)內(nèi)所有的進(jìn)程。
? ? ? ? pid<-1: 將信號(hào)傳給指定進(jìn)程組的所有進(jìn)程。這個(gè)進(jìn)程組號(hào)等于 pid 的絕對(duì)值。
? ? signum:信號(hào)的編號(hào)
返回值:
? ? 成功:返回 0
? ? 失?。悍祷?-1
代碼示例:?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc, char* argv[])
{
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork is error:");
exit(1);
}
else if (pid == 0)//子進(jìn)程的代碼區(qū)
{
int i = 0;
for (i = 0; i < 5; i++)
{
printf("in son process\n");
sleep(1);
}
}
else//父進(jìn)程的代碼區(qū)
{
printf("in father process\n");
sleep(2);
printf("kill sub process now \n");
kill(pid, SIGINT);
}
return 0;
}
注意:
????????使用 kill 函數(shù)發(fā)送信號(hào),接收信號(hào)進(jìn)程和發(fā)送信號(hào)進(jìn)程的所有者必須相同,或者 發(fā)送信號(hào)進(jìn)程的所有者是超級(jí)用戶。
5.2 alarm函數(shù)
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:?
? ? 定時(shí)器,鬧鐘,當(dāng)設(shè)定的時(shí)間到達(dá)時(shí),會(huì)產(chǎn)生SIGALRM信號(hào)
參數(shù):
? ? seconds:設(shè)定的秒數(shù)
返回值:?
? ? 如果alarm函數(shù)之前沒有alarm設(shè)置,則返回0
? ? 如果有,則返回上一個(gè)alarm剩余的時(shí)間
代碼示例:?
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int seconds = 0;
seconds = alarm(5);
printf("seconds = %d\n", seconds);
sleep(2);
seconds = alarm(5);
printf("seconds = %d\n", seconds);
while (1);
return 0;
}
5.3 setitimer函數(shù)(定時(shí)器)?
#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval
*old_value);
功能:
? ? 設(shè)置定時(shí)器(鬧鐘)。 可代替alarm函數(shù)。精度微秒us,可以實(shí)現(xiàn)周期定時(shí)。
參數(shù):
? ? which:指定定時(shí)方式
? ? ? ? a) 自然定時(shí):ITIMER_REAL → 14)SIGALRM計(jì)算自然時(shí)間
? ? ? ? b) 虛擬空間計(jì)時(shí)(用戶空間):ITIMER_VIRTUAL → 26)SIGVTALRM 只計(jì)算進(jìn)程占用cpu的時(shí)間
? ? ? ? c) 運(yùn)行時(shí)計(jì)時(shí)(用戶 + 內(nèi)核):ITIMER_PROF → 27)SIGPROF計(jì)算占用cpu及執(zhí)行系統(tǒng)調(diào)用的時(shí)間
? ? new_value:struct itimerval, 負(fù)責(zé)設(shè)定timeout時(shí)間
? ? struct itimerval {
? ? ? ? struct timerval it_interval; // 鬧鐘觸發(fā)周期
? ? ? ? struct timerval it_value; // 鬧鐘觸發(fā)時(shí)間
? ? };
? ? struct timeval {
? ? ? ? long tv_sec; // 秒
? ? ? ? long tv_usec; // 微秒
? ? }
? ? ? ? itimerval.it_value: 設(shè)定第一次執(zhí)行function所延遲的秒數(shù)
? ? ? ? itimerval.it_interval: 設(shè)定以后每幾秒執(zhí)行function
? ? old_value: 存放舊的timeout值,一般指定為NULL
返回值:
? ? 成功:0
? ? 失?。?1
代碼示例:?
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void myfunc(int sig)
{
printf("hello\n");
}
int main(int argc, char* argv[])
{
struct itimerval new_value;
//定時(shí)周期
new_value.it_interval.tv_sec = 1;
new_value.it_interval.tv_usec = 0;
//第一次觸發(fā)的時(shí)間
new_value.it_value.tv_sec = 2;
new_value.it_value.tv_usec = 0;
signal(SIGALRM, myfunc); //信號(hào)處理
setitimer(ITIMER_REAL, &new_value, NULL); //定時(shí)器設(shè)置
while (1);
return 0;
}
?5.4 raise函數(shù)
#include <signal.h>
int raise(int signum);
功能:
? ? 給調(diào)用進(jìn)程本身送一個(gè)信號(hào)。
參數(shù):
? ? signum:信號(hào)的編號(hào)。
返回值:
? ? 成功:返回 0
? ? 失敗:返回 非0raise(sig) <==> kill(getpid(),sig)
代碼示例:?
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char const* grgv[])
{
int num = 0;
while (1) {
printf("hello world\n");
sleep(1);
num++;
//循環(huán)執(zhí)行5秒后,進(jìn)程退出
if (num == 5) {
raise(SIGINT);
//kill(getpid(), SIGINT);
}
}
return 0;
}
5.5 abort函數(shù)
#include <stdlib.h>
void abort(void);
功能:
? ? 向進(jìn)程發(fā)送一個(gè) SIGABRT 信號(hào),默認(rèn)情況下進(jìn)程會(huì)退出
參數(shù):
? ? 無
返回值:
? ? 無
注意:
????????即使 SIGABRT 信號(hào)被加入阻塞集,一旦進(jìn)程調(diào)用了 abort 函數(shù),進(jìn)程也還是會(huì)被終止,且在終止前會(huì)刷新緩沖區(qū),關(guān)文件描述符。
代碼示例:?
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char const* grgv[])
{
int num = 0;
while (1) {
printf("hello world\n");
sleep(1);
num++;
//循環(huán)執(zhí)行5秒后,進(jìn)程退出
if (num == 5) {
abort();
}
}
return 0;
}
5.6 pause函數(shù)
#include <unistd.h>
int pause(void);
功能:
? ? 將調(diào)用進(jìn)程掛起直至捕捉到信號(hào)為止。這個(gè)函數(shù)通常用于判斷信號(hào)是否已到。
參數(shù):
? ? 無
返回值:
? ? 直到捕獲到信號(hào),pause 函數(shù)才返回-1,且 errno 被設(shè)置成 EINTR。
代碼示例:?
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char* argv[])
{
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fail to fork");
exit(1);
}
else if (pid > 0)//父進(jìn)程的代碼區(qū)
{
printf("in father process\n");
pause();
}
else//子進(jìn)程的代碼區(qū)
{
printf("in son process\n");
sleep(3);
kill(getpid(), SIGINT);
}
return 0;
}
5.7 signal函數(shù)
#include <signal.h>
void (*signal(int sig,void(*func)(int)))(int)
? ? typedef void (*sighandler_t)(int);
? ? sighandler_t signal(int signum,sighandler_t handler);
功能:?
? ? 當(dāng)進(jìn)程中產(chǎn)生某一個(gè)信號(hào)時(shí),對(duì)當(dāng)前信號(hào)進(jìn)行處理
參數(shù):?
? ? sig:指定要處理的信號(hào)
? ? handler:處理方式
? ? ? ? SIG_INT 當(dāng)信號(hào)產(chǎn)生時(shí),以缺?。ê雎裕┓绞教幚?br> ? ? ? ? SIG_DFL 當(dāng)信號(hào)產(chǎn)生時(shí),以當(dāng)前信號(hào)默認(rèn)的方式處理
? ? ? ? void handler(int sig):當(dāng)信號(hào)產(chǎn)生時(shí),通過信號(hào)處理函數(shù)自定義方式處理,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 函數(shù)名可以隨便寫,參數(shù)表示當(dāng)前的信號(hào)
返回值:
? ? 成功:第一次返回 NULL,下一次返回此信號(hào)上一次注冊(cè)的信號(hào)處理函數(shù)的地址。如果需要使用此返回
值,必須在前面先聲明此函數(shù)指針的類型。
? ? 失?。篠IG_ERR
代碼示例:?
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
void handler(int sig);
int main(int argc, char* argv[])
{
//以默認(rèn)的方式處理信號(hào)
#if 0
if (signal(SIGINT, SIG_DFL) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
#endif
//以忽略的方式處理信號(hào)
#if 0
if (signal(SIGINT, SIG_IGN) == SIG_ERR) {
perror("fail to siganl");
exit(1);
}
if (signal(SIGQUIT, SIG_IGN) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
#endif
//以用戶自定義方式處理信號(hào)
#if 0
if (signal(SIGINT, handler) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
if (signal(SIGQUIT, handler) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
#endif
while (1) {
printf("hello world\n");
sleep(1);
}
void handler(int sig) {
if (sig == SIGINT) {
printf("SIGINT正在處理\n");
}
if (sig == SIGQUIT) {
printf("SIGQUIT正在處理\n");
}
}
return 0;
}
返回值:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
void handler(int sig);
void* ret_handler;
void handler(int sig) {
printf("******************************\n");
printf("nihao beijing\n");
printf("welcome to hangzhou\n");
printf("******************************\n");
if (signal(SIGINT, ret_handler) == SIG_ERR) {
perror("fail to signal");
exit(1);
}
}
int main(int argc, char* argv[])
{
if ((ret_handler = signal(SIGINT, handler)) == SIG_ERR){
perror("fail to siganl");
exit(1);
}
while (1) {
printf("hello world\n");
sleep(1);
}
return 0;
}
6. 信號(hào)集
6.1 信號(hào)集概述
? ? ? ? 一個(gè)用戶進(jìn)程常常需要對(duì)多個(gè)信號(hào)做出處理。為了方便對(duì)多個(gè)信號(hào)進(jìn)行處理,在Linux系統(tǒng)中引入了信號(hào)集。
? ? ? ? 信號(hào)集是用來表示多個(gè)信號(hào)的數(shù)據(jù)類型。
6.2 信號(hào)集數(shù)據(jù)類型
? ? ? ? sigset_t
6.3 定義路徑:
? ? ? ??/usr/include/x86_64-linux-gnu/bits/sigset.h? ?(ubuntu12.04)
?6.4 信號(hào)集相關(guān)的操作主要有以下幾個(gè)函數(shù):
- sigemptyset
- sigfillset
- sigismember
- sigaddset
- sigdelset
1----sigemptyset()
#include <signal.h>
int sigemptyset(sigset_t *set);
功能:
初始化由 set 指向的信號(hào)集,清除其中所有的信號(hào)即初始化一個(gè)空信號(hào)集。
參數(shù):
set:信號(hào)集標(biāo)識(shí)的地址,以后操作此信號(hào)集,對(duì) set 進(jìn)行操作就可以了。
返回值:
成功:返回 0
失敗:返回 -1
2----sigfillset()
#include <signal.h>
int sigfillset(sigset_t *set);
功能:
初始化信號(hào)集合 set, 將信號(hào)集合設(shè)置為所有信號(hào)的集合。
參數(shù):
信號(hào)集標(biāo)識(shí)的地址,以后操作此信號(hào)集,對(duì) set 進(jìn)行操作就可以了。
返回值:
成功:返回 0
失敗:返回 -1
3----sigismember()
#include <signal.h>
int sigismember(const sigset_t *set,int signum);
功能:
查詢 signum 標(biāo)識(shí)的信號(hào)是否在信號(hào)集合 set 之中。
參數(shù):
set:信號(hào)集標(biāo)識(shí)符號(hào)的地址。
signum:信號(hào)的編號(hào)。
返回值:
在信號(hào)集中返回 1,不在信號(hào)集中返回 0
錯(cuò)誤:返回 -1
4----sigaddset()
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
功能:
將信號(hào) signum 加入到信號(hào)集合 set 之中。
參數(shù):
set:信號(hào)集標(biāo)識(shí)的地址。
signum:信號(hào)的編號(hào)。
返回值:
成功:返回 0
失敗:返回 -1
5----sigdelset()
#include <signal.h>
int sigdelset(sigset_t *set, int signum);
功能:
將 signum 所標(biāo)識(shí)的信號(hào)從信號(hào)集合 set 中刪除。
參數(shù):
set:信號(hào)集標(biāo)識(shí)的地址。
signum:信號(hào)的編號(hào)。
返回值:
成功:返回 0
失?。悍祷?-1
代碼案例:?
#include<stdio.h>
#include<signal.h>
v
int main(int argc, char* argv[])
{
//創(chuàng)建一個(gè)信號(hào)集
sigset_t set;
int ret = 0;
//初始化一個(gè)空的信號(hào)集
sigemptyset(&set);
//判斷SIGINT信號(hào)是否在信號(hào)集中
ret = sigismember(&set, SIGINT);
if (ret == 0) {
printf("SIGINT is not a member of sigprocmask\n ret=%d\n", ret);
}
//將指定的信號(hào)添加到信號(hào)集中
sigaddset(&set, SIGINT);
sigaddset(&set, SIGQUIT);
ret = sigismember(&set, SIGINT);
ir(ret == 1) {
printf("SIGINT is a member of sigprocmask\n ret=%d\n", ret);
}
return 0;
}
7. 信號(hào)阻塞集(屏蔽集、掩碼)
????????每個(gè)進(jìn)程都有一個(gè)阻塞集,它用來描述哪些信號(hào)遞送到該進(jìn)程的時(shí)候被阻塞(在信 號(hào)發(fā)生時(shí)記住它,直到進(jìn)程準(zhǔn)備好時(shí)再將信號(hào)通知進(jìn)程)。
???????? 所謂阻塞并不是禁止傳送信號(hào), 而是暫緩信號(hào)的傳送。若將被阻塞的信號(hào)從信號(hào)阻 塞集中刪除,且對(duì)應(yīng)的信號(hào)在被阻塞時(shí)發(fā)生了,進(jìn)程將會(huì)收到相應(yīng)的信號(hào)。
7.1 sigprocmask函數(shù)
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:
檢查或修改信號(hào)阻塞集,根據(jù) how 指定的方法對(duì)進(jìn)程的阻塞集合進(jìn)行修改,新的信號(hào)阻塞集由 set 指定,而原先的信號(hào)阻塞集合由 oldset 保存。
參數(shù):
how:信號(hào)阻塞集合的修改方法。
SIG_BLOCK:向信號(hào)阻塞集合中添加 set 信號(hào)集
SIG_UNBLOCK:從信號(hào)阻塞集合中刪除 set 集合
SIG_SETMASK:將信號(hào)阻塞集合設(shè)為 set 集合
set:要操作的信號(hào)集地址。
oldset:保存原先信號(hào)集地址。
注:若 set 為 NULL,則不改變信號(hào)阻塞集合,函數(shù)只把當(dāng)前信號(hào)阻塞集合保存到oldset 中。
返回值:
成功:返回 0
失?。悍祷?-1
代碼示例:?
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
int i = 0;
//創(chuàng)建一個(gè)信號(hào)集
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
while(1){
//將set信號(hào)集添加到信號(hào)阻塞集中
sigprocmask(SIG_BLOCK, &set, NULL);
for (i = 0; i < 5; i++) {
printf("SIGINT signal is blocked\n");
sleep(1);
}
//將set信號(hào)集從信號(hào)阻塞集中刪除
sigprocmask(SIG_UNBLOCK, &set, NULL);
for (i = 0; i < 5; i++) {
printf("SIGINT signal unblocked\n");
sleep(1);
}
}
return 0;
}
7.2 sigpending函數(shù)
#include <signal.h>
int sigpending(sigset_t *set);
功能:
讀取當(dāng)前進(jìn)程的未決信號(hào)集
參數(shù):
set:未決信號(hào)集
返回值:
成功:0
失?。?1
代碼示例:?文章來源:http://www.zghlxwxcb.cn/news/detail-517324.html
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
// 自定義信號(hào)集
sigset_t myset, old;
sigemptyset(&myset);// 清空 -》 0
// 添加要阻塞的信號(hào)
sigaddset(&myset, SIGINT);
sigaddset(&myset, SIGQUIT);
sigaddset(&myset, SIGKILL);
// 自定義信號(hào)集設(shè)置到內(nèi)核中的阻塞信號(hào)集
sigprocmask(SIG_BLOCK, &myset, &old);
sigset_t pend;
int i = 0;
while (1)
{
// 讀內(nèi)核中的未決信號(hào)集的狀態(tài)
sigpending(&pend);
for (int i = 1; i < 32; ++i)
{
if (sigismember(&pend, i))
{
printf("1");
}
else if (sigismember(&pend, i) == 0)
{
printf("0");
}
}
printf("\n");
sleep(1);
i++;
// 10s之后解除阻塞
if (i > 10)
{
// sigprocmask(SIG_UNBLOCK, &myset, NULL);
sigprocmask(SIG_SETMASK, &old, NULL);
}
}
return 0;
}
總結(jié):
????????信號(hào)機(jī)制是操作系統(tǒng)中用于處理異步事件的一種強(qiáng)大工具,它提供了一種處理程序中非預(yù)期事件(如硬件錯(cuò)誤、特定的用戶交互等)的方法。理解和有效使用信號(hào)機(jī)制,可以幫助我們編寫更健壯、更穩(wěn)定的程序??偟膩碚f,信號(hào)是進(jìn)程通信的重要方式之一,它的理解和掌握對(duì)于系統(tǒng)編程人員至關(guān)重要。文章來源地址http://www.zghlxwxcb.cn/news/detail-517324.html
到了這里,關(guān)于【信號(hào)】信號(hào)處理與進(jìn)程通信:快速上手的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!