linux下公有64個信號,kill -l 查看一下:
可以看到,缺少了32、33兩個未知信號,從這里分界,前面31個信號是不可靠信號,后面的是可靠信號。當(dāng)進程發(fā)生阻塞的時候(一下子發(fā)送很多信號),不可靠信號容易丟失。如何去驗證呢?可以在2(不可靠信號)號信號和34(可靠進程)號信號屏蔽期間,不斷向某個進程發(fā)送這兩個信號,待解除屏蔽后,觀察是否丟失。這里測試的時候,要注意一下,9-SIGKILL 19-SIGSTOP 31 32 這4個信號是不能被捕獲的,遍歷以下所有信號就可以發(fā)現(xiàn)了。
平度網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站開發(fā)等網(wǎng)站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯(lián)成立于2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)。
首先,講一下信號集,顧名思義,存放信號的集合。
信號集的操作函數(shù)有以下幾個,具體使用,后面再說。
第一種是利用signal,kill函數(shù)。
#include < signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal()有兩個參數(shù):信號編號和處理函數(shù)(sighandler_t是一個函數(shù)指針),返回值也是一個sighandler_t類型的,這里返回的是之前的信號處理函數(shù)。
信號處理函數(shù)是一個帶int參數(shù),返回值為void的函數(shù)。handler也可以是兩個特殊的值:SIG_IGN 屏蔽該信號 SIG_DFL 恢復(fù)默認行為
#include < sys/types.h>
#include < signal.h>
int kill(pid_t pid, int sig);
kill()的作用是把信號sig發(fā)送給進程pid。
#include
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:讀取過更改進程的信號屏蔽字。
返回值:成功為0,失敗為-1
參數(shù):如果oset是非空指針,則讀取進程的當(dāng)前信號屏蔽字通過oset參數(shù)傳出(就是將原來的信號屏蔽字備份到oset);set是更改進程的信號屏蔽字,how指示如何修改。how的可選值如下:
代碼如下:
// 3.不可靠信號的丟失
void handler(int no)
{
printf("received a signal: %d\n",no);
}
int main()
{
pid_t pid;
sigset_t set;
sigset_t oset;
int i;
sigemptyset(&set); //清空
sigaddset(&set,2); //添加2號信號
sigaddset(&set,34); //添加34號信號
for(i = 1 ; i <= 64 ; i++) //查看集合狀態(tài)
{
if(sigismember(&set,i) == 1)
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
sigprocmask(SIG_SETMASK,&set,&oset); //將這個集合設(shè)置為這個進程的阻塞信號集
//綁定信號
signal(2,handler);
signal(34,handler);
sleep(50); //在此期間,向該進程發(fā)送多次2、34號信號
sigprocmask(SIG_SETMASK,&oset,NULL);//解除綁定
while(1)
{
}
return 0;
}
在另一個終端(20s內(nèi)),發(fā)送信號:
結(jié)果,可以看到,不可靠信號,只收到了一次:
第二種是sigacton函數(shù)。
#include
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
功能:用于改變進程接收到特定信號后的行為。
參數(shù):signum 除了SIGKILL 和SIGSTOP(為這兩個信號定義自己的處理函數(shù),將導(dǎo)致信號安裝錯誤);
第二個參數(shù)是指向結(jié)構(gòu)sigaction的一個實例的指針,在結(jié)構(gòu)sigaction的實例中,制定了對特定信號的處理,可以為空,進程會以缺省方式對信號處理;
old用來保存原來對信號的處理,可以為NULL。
返回值:成功為0,失敗-1
sigaction結(jié)構(gòu)體
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
參數(shù):
前兩個參數(shù)sa_handler和sa_sigaction都是自定義信號處理函數(shù),同樣,sa_handler有兩個默認值:SIG_DFL和SIG_IGN。區(qū)別在于sa_sigaction是為實時信號而設(shè)定的(也支持非實時信號),第二個參數(shù)是指向siginfo_t結(jié)構(gòu)的指針,結(jié)構(gòu)中包含信號攜帶的數(shù)據(jù)值,第三個參數(shù)暫時沒有使用(POSIX沒有規(guī)范使用該指針的標準);
sa_mask是屏蔽信號集;
sa_flags有以下幾個值:
重點掌握2個:一個是設(shè)置為0,表示默認屬性;一個是設(shè)置為SA_SIGINFO,那么此時處理函數(shù)不再使用sa_handler,而是sa_sigaction.
那么sa_sigaction的結(jié)構(gòu)體參數(shù)長什么樣呢?
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
void *si_addr; /* Memory location which caused fault */
天哪,肯定記不住。不需要記,用到的時候,查一下就好了。
這里掌握兩個,一個是si_signum,不用說了吧,一個是si_value。這是什么?這是在發(fā)送信號時攜帶的一個數(shù)據(jù),數(shù)據(jù)類是sigval,這是一個聯(lián)合體。
typedef union sigval
{
int sival_int;
void *sival_ptr;
}sigval_t;
sigqueue函數(shù)
#include < signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
sigqueue()類似于之前的kill()。是用來發(fā)送信號的,主要針對有帶參的信號,與sigaction()配合使用。
第三個參數(shù)是一個聯(lián)合數(shù)據(jù)結(jié)構(gòu)union sigval,指定了信號傳遞的參數(shù),即通常所說的4字節(jié)值。
具體代碼如下:
void handler(int signo,siginfo_t *resdata,void *unknowp)
{
printf("signo=%d\n",signo);
printf("return data :%d\n",resdata->si_value.sival_int);
}
int main()
{
int i = 5;
pid_t pid = 0;
pid = fork();
if(pid == -1)
{
perror("create fork");
return -1;
}
else if(pid == 0)
{
sleep(1);
//向父進程發(fā)送帶整型數(shù)據(jù)的信號
union sigval sigvalue;
sigvalue.sival_int = 111;
//發(fā)送信號
while(i--)
{
sigqueue(getppid(),2,sigvalue);
printf("send signal:2 success!\n");
sigqueue(getppid(),34,sigvalue);
printf("send signal:34 success!\n");
}
}
else
{
struct sigaction act;
//初始化sa_mask
sigemptyset(&act.sa_mask);
act.sa_sigaction=handler;
//一旦使用了sa_sigaction屬性,那么必須設(shè)置sa_flags屬性的值為SA_SIGINFO
act.sa_flags=SA_SIGINFO;
//注冊信號
sigaction(2,&act,NULL);
sigaction(34,&act,NULL);
}
while(1)
{
}
}
運行結(jié)果:
同樣,可以看到2號信號只收到了1次。