信号通信
信号通信很简单,将特定信号传递给进程,使进程进行相应动作,信号是软中断,只要执行过,就生效,不必一直卡死等待信号来临,以此达到通信的目的。linux
信号量有很多在文章最后列举;
信号通信函数结构
#include <signal.h>
void (*signal(int signo,void(*func)(int)))(int)
可以看到信号函数结构比较复杂
- signal:
本身是个函数指针,- signal函数参数:
- signo:
具体信号名称或者编号- func:
函数指针,指向信号处理函数,函数参数为int型
不写函数一般采用下面两个宏代替
SIG_IGN
忽略此信号
SIG_DFL
按默认的方式处理此信号
信号通信小例程:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void my_func(int sign_no)
{
if(sign_no==SIGINT)
printf("I have get SIGINT\n");
else if(sign_no==SIGQUIT)
printf("I have get SIGQUIT\n");
}
int main()
{
printf("Waiting for signal SIGINT or SIGQUIT \n ");
/*注册信号处理函数*/
signal(SIGINT, my_func);
signal(SIGQUIT, my_func);
pause();
exit(0);
}
在主函数中注册信号处理方式,这里没有采用两个宏处理,采用的是指定函数处理,注册完信号处理函数后,进程将会执行pause
等待信号来临,特定信号出现,将会跳进信号处理函数func
,结束进程。
试验方式是先将此进程跑起来,利用ps aux
指令获取进程ID
,采用kill
命令向进程传递信号,观察进程运行状况,达到进程通信的目的。
[root@localhost signal]# gcc -o mysignal mysignal.c
[root@localhost signal]# ls
mysignal mysignal.c
[root@localhost signal]# ./mysignal
Waiting for signal SIGINT or SIGQUIT
切换终端执行ps -aux
root 27544 0.0 0.4 11592 3308 ? Ss 21:03 0:04 sshd: root@pts/0
root 27548 0.0 0.2 6828 1696 pts/0 Ss+ 21:03 0:00 -bash
root 28112 0.0 0.1 3840 1016 ? S 22:51 0:00 /usr/libexec/hald-addon-rfkill-killswitch
root 28202 0.1 0.4 11592 3308 ? Rs 23:02 0:00 sshd: root@pts/1
root 28206 0.0 0.2 6720 1584 pts/1 Ss 23:02 0:00 -bash
postfix 28232 0.0 0.3 13440 2468 ? S 23:04 0:00 pickup -l -t fifo -u
root 28241 0.0 0.0 1848 352 tty2 S+ 23:06 0:00 ./mysignal
root 28243 0.0 0.1 6532 1040 pts/1 R+ 23:06 0:00 ps aux
查看到进程编号28241,向进程发送信号。
[root@localhost ~]# kill -s SIGQUIT 28241
另一终端查看进程运行情况:
[root@localhost signal]# ./mysignal
Waiting for signal SIGINT or SIGQUIT
I have get SIGQUIT
[root@localhost signal]#
可以看到进程接收到信号并执行相应动作。证明通信正常,这就是简单的信号通信。可以将信号注册函数中第二个参数改为SIG_IGN
(忽略收到的信号),即便使进程接收到信号,进程也不会动作。将信号注册函数第二个参数改为SIG_DFL
(按信号默认的方式处理),进程将会按信号特定的含义执行相应动作。这里不在演示。
信号让进程暂停的小例子
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int pid;
pid=fork();
if(pid==0)
{
signal(SIGCONT,SIG_DFL);
while(1)
{
printf("I an son\n");
sleep(2);
}
}else
{
sleep(10);
kill(pid,SIGSTOP);
sleep(20);
kill(pid,SIGCONT);
exit(0);
}
return 0;
}
信号列表
SIGHUP:本信号在用户终端结束时发出,通常是在终端的控制进程结束时,通知同一会话期内的各个作业,这时他们与控制终端不在关联。比如,登录linux
时,系统会自动分配给登录用户一个控制终端,在这个终端运行的所有程序,包括前台和后台进程组,一般都属于同一个会话。当用户退出时,所有进程组都将收到该信号,这个信号的默认操作是终止进程。此外对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
SIGINT:程序终止信号。当用户按下CRTL+C
时通知前台进程组终止进程。
SIGQUIT:Ctrl+\
控制,进程收到该信号退出时会产生core
文件,类似于程序错误信号。
SIGILL:执行了非法指令。通常是因为可执行文件本身出现错误,或者数据段、堆栈溢出时也有可能产生这个信号。
SIGTRAP:由断点指令或其他陷进指令产生,由调试器使用。
SIGABRT:调用abort
函数产生,将会使程序非正常结束。
SIGBUS:非法地址。包括内存地址对齐出错。比如访问一个4
个字长的整数,但其地址不是4
的倍数。它与SIGSEGV
的区别在于后者是由于对合法地址的非法访问触发。
SIGFPE:发生致命的算术运算错误。
SIGKILL:用来立即结束程序的运行。
SIGUSR1:留给用户使用,用户可自定义。
SIGSEGV:访问未分配给用户的内存区。或操作没有权限的区域。
SIGUSR2:留给用户使用,用户可自定义。
SIGPIPE:管道破裂信号。当对一个读进程已经运行结束的管道执行写操作时产生。
SIGALRM:时钟定时信号。由alarm
函数设定的时间终止时产生。
SIGTERM:程序结束信号。shell
使用kill产生该信号,当结束不了该进程,尝试使用SIGKILL
信号。
SIGSTKFLT:堆栈错误。
SIGCHLD:子进程结束,父进程会收到。如果子进程结束时父进程不等待或不处理该信号,子进程会变成僵尸进程。
SIGCONT:让一个停止的进程继续执行。
SIGSTOP:停止进程执行。暂停执行。
SIGTSTP:停止运行,可以被忽略。Ctrl+z
。
SIGTTIN:当后台进程需要从终端接收数据时,所有进程会收到该信号,暂停执行。
SIGTTOU:与SIGTTIN
类似,但在写终端时产生。
SIGURG:套接字上出现紧急情况时产生。
SIGXCPU:超过CPU
时间资源限制时产生的信号。
SIGXFSZ:当进程企图扩大文件以至于超过文件大小资源限制时产生。
SIGVTALRM:虚拟使用信号。计算的是进程占用CPU
调用的时间。
SIGPROF:包括进程使用CPU的时间以及系统调用的时间。
SIGWINCH:窗口大小改变时。
SIGIO:文件描述符准备就绪,表示可以进行输入输出操作。
SIGPWR:电源失效信号。
SIGSYS:非法的系统调用。