可以自己做网站服务器不,公司专业做网站,网站推荐界面,苏州批量关键词优化在《Linux C编程实战》笔记#xff1a;信号的捕捉和处理-CSDN博客的sigaction的sa_mask成员#xff0c;它的类型就是一个信号集#xff0c;下面我们来介绍它
信号集
信号的总数目达64个#xff0c;所以不能用一个整数表示它们的集合#xff0c;int类型通常是4字节32位信号的捕捉和处理-CSDN博客的sigaction的sa_mask成员它的类型就是一个信号集下面我们来介绍它
信号集
信号的总数目达64个所以不能用一个整数表示它们的集合int类型通常是4字节32位位数不够。POSIX标准定义了数据类型sigset_t来表示信号集并且定义了一系列函数来操作信号集
#includesignal.h
//初始化一个信号集使其不包括任何信号
int sigemptyset(sigset_t *set);//初始化一个信号集使其包括所有信号
int sigfillset(sigset_t *set);//向set指定的信号集中添加由signun指定的信号
int sigaddset(sigset_t *set,int signum);//从set指定的信号集中删除由signum指定的信号
int sigdelset(sigset_t *set,int signum);//测试信号signum是否包括在set指定的信号集中
int sigismember(const sigset_t *set,int signum);
前四个函数在执行成功时返回0失败返回-1.
sigismember返回1表示测试的信号在信号集中返回0表示信号不在信号集中出错返回-1.
注意在使用信号集前要对信号集调用一次sigemptyset或sigfillset来初始化它。
信号屏蔽
信号屏蔽又称信号阻塞
#includesignal.h
int sigprocmask(int how,const sigset_t *set,sigset *oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);
sigprocmask函数
每一个进程都有一个信号屏蔽码调用sigprocmask可以修改进程的信号屏蔽码。
当信号被屏蔽时如果有一个或多个屏蔽的信号到达它们会被挂起直到信号解除屏蔽。信号解除屏蔽后挂起的信号会被递送给进程但如果信号在解除屏蔽前多次到达不可靠信号只会递送一次可靠信号会按次数递送。 how此参数确定如何更改信号掩码。它可以取以下值之一 SIG_BLOCK将集合中的信号添加到当前信号掩码。SIG_UNBLOCK从当前信号掩码中移除集合中的信号。SIG_SETMASK将信号掩码设置为指定的集合。 set这是一个指向 sigset_t 对象的指针表示要阻塞、解除阻塞或设置的信号集具体取决于 how 参数的值。 oldset这是一个可选的指向 sigset_t 对象的指针用于存储先前的信号掩码。如果为 NULL则不保存先前的信号掩码。 sigprocmask 的返回值在成功时为 0在失败时为 -1同时设置 errno 以指示错误。 sigpending函数
函数sigpending函数用来获取调用进程因被阻塞但已经产生的未决信号集。该信号集通过参数set返回。
成功返回0有错误发生返回-1错误代码存入errno。
示例程序1
该程序演示了sigprocmask和sigpending的用法
#includestdio.h
#includestdlib.h
#includesignal.h
#includeunistd.h
//自定义的错误处理函数这个以前都讲过
void my_err(const char *err_string,int line){fprintf(stderr,line:%d ,line);perror(err_string);exit(1);
}
//SIGINT的信号处理函数
void handler_sigint(int signo){printf(recv SIGINT\n);
}
int main(int argc,char **argv){//定义了几个信号集sigset_t newmask,oldmask,pendmask;//安装信号处理函数if(signal(SIGINT,handler_sigint)SIG_ERR)//安装失败的错误处理这个SIG_ERR在signal这一节也讲过my_err(signal,__LINE__);//这里可以发送SIGINT信号测试一下这时候是可以响应的sleep(10);sigemptyset(newmask);//初始化newmasksigaddset(newmask,SIGINT);//将SIGINT添加进去if(sigprocmask(SIG_BLOCK,newmask,oldmask)0)//尝试将SIGINT添加到进程的屏蔽屏蔽码中去用的是SIG_BLOCKmy_err(sigprocmask,__LINE__);else printf(SIGINT blocked\n);sleep(10);//睡一会//获取未决的信号队列我们操作的时候应该在睡眠的时候发送一次SIGINT信号来测试if(sigpending(pendmask)0)my_err(sigpending,__LINE__);//用sigismember查看未决信号集里是否有SIGINTswitch (sigismember(pendmask,SIGINT)){case 0:printf(SIGINT is not in pending queue\n);break;case 1:printf(SIGINT is in pending queue\n);break;case -1:my_err(sigismember,__LINE__);break;default:break;}//再解除对SIGINT的屏蔽,就是把原先的信号屏蔽码又设置回去if(sigprocmask(SIG_SETMASK,oldmask,nullptr)0)my_err(sigprocmask,__LINE__);else printf(SIGINT unblocked\n);while(1);return 0;
} 看运行结果一开始我发送SIGINT信号处理函数有用然后SIGINT被阻塞了这时候我发了四个SIGINT根据不可靠信号的阻塞最后只有一个信号会被递送所以程序只打印了一次recv SIGINT之后阻塞解除我再发送SIGINT也可以正常接收。
sigsuspend函数 sigsuspend 函数用于临时修改信号屏蔽字signal mask并挂起进程直到收到一个信号为止。 函数的作用可以分为两步 临时替换当前信号屏蔽字为 mask。挂起进程直到接收到一个信号。 当进程接收到一个信号后sigsuspend 会恢复原始的信号屏蔽字并返回。这个函数通常用于实现原子操作即在某些关键操作期间阻塞特定的信号以确保该操作不会被信号中断。 这个函数总是返回-1并将errno置为EINTR
示例程序2
#includestdio.h
#includestdlib.h
#includesignal.h
#includeunistd.h
void my_err(const char *err_string,int line){fprintf(stderr,line:%d ,line);perror(err_string);exit(1);
}
void handler_sigint(int signo){printf(\nrecv SIGINT\n);
}
int main(int argc,char **argv){sigset_t newmask,oldmask,zeromask;if(signal(SIGINT,handler_sigint)SIG_ERR)my_err(signal,__LINE__);sigemptyset(newmask);sigemptyset(zeromask);sigaddset(newmask,SIGINT);if(sigprocmask(SIG_BLOCK,newmask,oldmask)0)my_err(sigprocmask,__LINE__);else printf(SIGINT blocked\n);//前面和上一个示例都是一样的/*临界区*///使用sigsuspend取消所有信号的屏蔽并等待信号的触发因为zeromask是空的信号集if(sigsuspend(zeromask)!-1)//sigsuspend总是返回-1my_err(sigsuspend,__LINE__);else printf(recv a signo,return from sigsuspend\n);/*------------------------------//使用sigprocmask加上pause可能会出现错误if(sigprocmask(SIG_SETMASK,oldmask,nullptr)0)my_err(sigprocmask,__LINE__);pause();---------------------------*///下面也是一样恢复屏蔽字if(sigprocmask(SIG_SETMASK,oldmask,nullptr)0)my_err(sigprocmask,__LINE__);else printf(SIGINT unblocked\n);while(1);return 0;
}
程序首先用sigprocmask屏蔽掉信号SIGINT然后使用sigsuspend()取消对所有信号的屏蔽并挂起等待信号的触发。 然后随便发送一个信号 这是按书上的步骤不过我觉得问题很大书上随便发了个SIGRTMIN的信号但是由于我们没有给这个信号注册信号处理函数所以进程默认直接结束了。这句话也没有执行 else printf(recv a signo,return from sigsuspend\n);
这回我们发SIGINT信号 虽然进程一开始屏蔽了SIGINT信号但是我们调用了sigsuspend函数并且这个例子里的sigsuspend函数的信号集是空的它会取消对所有信号的屏蔽然后挂起所以我们发送SIGINT进程这时是可以接收的。可以看到进程首先调用了SIGINT的处理函数之后sigsuspend函数返回-1函数返回前会把屏蔽字恢复成原来的情况也就是SIGINT被阻塞执行了之前没有执行的打印语句。
如果使用注释掉的那段代码会有风险。如果信号发生在sigprocmask之后pause之前则这个信号可能就会丢失了如果信号只发生一次程序将永远挂起在pause上。