进程间通信方式--信号
信号(sginal)
信号的定义
信号是linux系统响应某些条件而产生的一个事件,接收到信号的进程会采取相应的措施。通常喜好是因为一个错误产生的。也可以作为进程间通信的一种方式,由一个进程发送给另一个进程。信号的产生叫做生成,接收叫做捕获。
信号的本质
信号是在软件层次上对中断机制的一种模拟,一个进程接收到信号和处理器收到一个中断请求是一样的。
信号是进程间通信机制中唯一的异步通信,进程不需要等待信号的到达,进程也不知道信号到达的时间。
信号的来源
信号的来源主要有两种:
1.硬件来源(按下键盘按键);
2.软件来源,包括kill,raise,alarm等函数;
信号可以直接进行用户空间进程和内核空间进程之间的交互,内核空间的进程可以通过信号来通知用户空间一些系统事件。
如果一个进程没有处在执行态,信号就存放在内核空间中,直到该进程恢复执行。
信号的产生
1.按下终端键
2.硬件异常
3.软件异常
4.调用kill()函数
5.运行kill命令
Linux所支持的信号
信号名 | 含义 | 默认操作 |
---|---|---|
SIGHUP | 终端挂起或者控制进程终止 | 终止进程 |
SIGINT | 键盘中断(如break键被按下) | 终止进程 |
SIGQUIT | 键盘的退出键被按下 | 终止进程并进行内核映像转储(dump core) |
SIGILL | 非法指令 | 终止进程并进行内核映像转储(dump core) |
SIGABRT | 由abort(3)发出的退出指令 | 终止进程并进行内核映像转储(dump core) |
SIGFPE | 浮点异常 | 终止进程并进行内核映像转储(dump core) |
SIGKILL | Kill信号 | 终止进程,信号不能被捕获,不能被忽略 |
SIGSEGV | 无效的内存引用 | 终止进程并进行内核映像转储(dump core) |
SIGPIPE | 管道破裂: 写一个没有读端口的管道 | 终止进程 |
SIGALRM | 由alarm(2)发出的信号 | 终止进程 |
SIGTERM | 终止信号 | 终止进程 |
SIGUSR1 | 用户自定义信号1 | 终止进程 |
SIGUSR2 | 用户自定义信号2 | 终止进程 |
SIGCHLD | 子进程结束信号 | 忽略信号 |
SIGCONT | 进程继续(曾被停止的进程) | |
SIGSTOP | 终止进程 | 停止进程,信号不能被捕获,不能被忽略 |
SIGTSTP | 控制终端(tty)上按下停止键 | 停止进程 |
SIGTTIN | 后台进程企图从控制终端读 | 停止进程 |
SIGTTOU | 后台进程企图从控制终端写 | 停止进程 |
信号的发送
发送信号的函数有:kill()、raise()、sigqueue()、alarm()、setitimer()、abort()。
kill-发送信号给指定进程
函数原型
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int signo);
参数
- pid:指定发送信号的接收线程,getpid(),表示向自身发信号,等价于raise
- signo:信号的大小signum
参数pid
参数pid的值 | 接收信号的进程 |
---|---|
pid>0 | 进程ID为pid的进程 |
pid=0 | 同一个进程组中的进程 |
pid<0 pid!=-1 | 进程组ID为-pid的所有进程 |
pid=-1 | 除发送进程外,所有进程ID大于1的进程 |
参数signo
Signo是信号值,当为0时(即空信号),实际不发送任何信号,但照常进行错误检查,因此,可用于检查目标进程是否存在,以及当前进程是否具有向目标发送信号的权限(root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程发送信号)。
Kill()最常用于pid>0时的信号发送,调用成功返回 0; 否则,返回 -1。
下面程序,完成了父进程和子进程交替输出5次,然后父进程发送信号终止子进程,父进程继续循环输出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int main(int argc, char *argv[])
{
pid_t pid;
int i = 0;
//创建进程
pid = fork();
//出错
if(pid < 0){
printf("fork process failed!\n");
exit(1);
}else if(pid == 0){
//子进程
while(1){
printf("I am child process ,my pid is: %d\n", getpid());
sleep(3);
}
}else{
//父进程
while(1){
printf("I am parent process ,my pid is: %d\n", getpid());
sleep(3);
i++;
if(i == 2){
kill(pid, SIGINT);
}
}
}
return 0;
}
raise-向自己发送信号
向进程本身发送信号,参数为即将发送的信号值。
调用成功返回0;否则,返回-1.
函数原型
#include <signal.h>
int raise(int signo);
下面的程序,进程通过raise向自身发送了一个SIGINT信号。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, char *argv[])
{
int i = 0;
while(1){
i++;
if(i ==3){
printf("I will raise a SIGINT to myself!\n");
//发送SIGINT给进程自身
raise(SIGINT);
}
//进程正常运行
printf("I am running!\n");
sleep(1);
}
return 0;
}
alarm-设置信号传送闹铃
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
专门为SIGALRM信号而设,在指定的时间seconds秒后,将向进程本身发送SIGALRM信号,又称为闹钟时间。
进程调用alarm后,任何以前的alarm()调用都将无效。如果参数seconds为零,那么进程内将不再包含任何闹钟时间。
返回值,如果调用alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。
abort–终止进程
#include <stdlib.h>
void abort(void);
向进程发送SIGABORT信号,默认情况下进程会异常退出,当然可定义自己的信号处理函数。即使SIGABORT被进程设置为阻塞信号,调用abort()后,SIGABORT仍然能被进程接收。该函数无返回值。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("Calling abort()\n");
abort();
/* The next code will never reach... */
printf("after abort...\n");
return 0;
}