一个最简单的信号信号处理例子:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
void signal_rec(int signum, siginfo_t *info, void *myop)
{
printf("receive signal %d\n", signum);
sleep(5);
}
int main(int argc,char **argv)
{
struct sigaction act;
int sig,i;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = signal_rec;
for(i=1; i<argc; i++){ //argv[0]为调用程序名
sig = atoi(argv[i]);
if(sigaction(sig, &act, NULL) <0){
printf("install signal error\n");
}
}
while(1){
sleep(2);
printf("wait for the signal\n");
}
}
用法:
将文件保存为test.c,执行make test,编译生成test文件。
./test 36 39&
命令的意思是注册信号36,39。命令结果会返回pid,假设为2625。
通过另外一个终端向2625进程发送信号。例如:kill -s 36 2625
则我们可以看到signal_rec函数被执行了。
当我们发送40信号,我们会发送程序终止了,这是因为对于实时信号,默认的操作是终止。
关于信号:
Linux
支持的信号分为可靠信号和不可靠信号。此处的可靠与不可靠不是指系统是不是可靠的可靠,而是对于可靠信息来说,每一次信号发实都每被加到信号链中,所以是
可靠的;而对于不可靠信号来说,如果进程之前已经接收到该信号,则不会被加到信号链中,因此对于此次发送的信号来说,对于该进程来说是不知道的,所就是说
信号丢失了,因此是不可靠的。
不可靠信号主要是在早期信号机制上的信号。一般来说,信号值小于SIGRTMIN的信号为不可靠信号,不可靠信号又称为非实时信号。可靠信号又称为实时信号。实时信号是SIGRTMIN和SIGRTMAX间的所有信号。
我们可以通过kill -l查看SIGRTMIN和SIGRTMAX的值。在Debian系统和Redhat上面,一般SIGRTMIN=33,SIGRTMAX=64。
Linux既支持新的信号安装函数sigation以及信号发送函数sigqueue,又支持早期的signal信号安装函数和kill信号发送函数。
信号的可靠与不可靠只与信号值有关,与信号的发送和安装函数无关,也就是说在Linux下即使使用sigaction和sigqueue也不可能将不可靠信号变为可靠信号。
信号发送函数主要有以下几个:kill,raise,sigqueue,alarm,settimer,abort。
信号安装函数主要有signal和sigaction。sigaction主要用于与sigqueue系统调用配合使用,主要用于实时信号处理。
信号集操作主要有以下几个函数:sigemptyset,sigfillset,sigaddset,sigdelset,sigismember。
信号的阻塞的未决主要有以下几个函数:sigprocmask,sigsuspend,sigpending。
最后以一个读串口设备时用到的信号处理作为结尾(在上次的初始化串口设备中已经出现过):
在读取设备数据或者进行网络应用的时候,为了防止程序进入死锁,我们需要设置超时操作,即比如我们读串口设备,尝试一定时间后仍然没有响应,则可能设备没有正常工作。那么在超时以后我们需要退出,否则程序就锁住了。
我们现在使用SIGALRM信号来进行这个处理(这种方式并不是最好的办法):
我们假设有一个标记是否超时的全局变量caught_alrm,默认为0,为1时则表示超时。
static volatile sig_atomic_t caught_alrm;
static void sig_alrm(int signo){//信号处理函数,设置超时全局变量为1。
caught_alrm = 1;
return;
}
int a_function{
……
if(signal(SIGALRM, sig_alrm) == SIG_ERR){
syslog(LOG_ERR,"signal error in function:%s",__FUNCTION__);
return -1;
}
caught_alrm = 0;
alarm(expalarm);
do{
//do something
//if the work is finished,call alarm(0) to clean the timer.
}while(caught_alrm == 0);
}
注:
1、本文为整理以前的工作笔记,如果您要转载,请注意来源为尔雅,作者覃士国。如果您有任何问题欢迎交流:shiguo.qin@gmail.com
2、
此文仅仅是一则笔记,如果您正在寻找关于Linux信号编程方面的资料,可以参考郑彦兴的一篇文章:http://www-
128.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html。此文详细描述了很多关于信
号处理中的结构等内容,是学习信号编程的一篇不错的教程式文章。