进程间通信-软中断
内容
- 使用软中段机制实现Linux进程间通信
机理说明
软中断信号(signal)是一种简单且最基本的进程通信机制,它最大的特点是提供了一种简单的处理异步事件的方法。例如,常见的用户从键盘键入组合键 Ctrl+C 来中断一个程序的运行,或者在两个进程之间通过某个信号来通知发生了异步事件,或者向系统或进程报告突发的硬件故障,如非法指令、运算溢出等。更重要的是,用户进程还可以向自己发送信号以中断进程的执行,并自动转入指定的软中断处理函数去执行用户自行安排的处理内容,处
理完毕后再返回用户进程继续执行,从而为应用程序提供了由用户自行处理随机事件的通信机制。软中断信号实现 (signal implementation) 是操作系统用来通知进程有事情发生的一种机制。由于这种信号总是在进程处于运行状态时才会去响应,故称之为软中断信号。软中断信号的使用者是操作系统和源程序,操作系统事先将系统的中可以使用的软件中断信号进行集中编码并定义相应含义后,提交用户使用。用户可以通过相应的软件中断序号或软中断名称来使用软中断,二者在使用上是等效的。用户只能在操作系统提供的软件中断序号范围内使用软件中断信号,不能自己创建新的软件中断信号。如果用户的应用程序之间有信号需要发送,则可以使用操作系统预留给用户使用的用户信号 SIGUSR1 或用户信号 SIGUSR2。
序号 | 名称 | 含义 |
---|---|---|
1 | SIGHUP | 挂起 |
2 | SIGINT | Ctrl+C |
3 | SIGQUIT | Ctrl+\ |
4 | SIGILL | 非法指令 |
5 | SIGTRAP | 自陷,跟踪代码执行 |
6 | SIGIOT | IOT指令 |
7 | SIGBUS | 总线错 |
8 | SIGFPE | 浮点数例外 |
9 | SIGKILL | 终止进程 |
10 | SIGUSR1 | 用户定义信号1 |
11 | SIGEGV | 段越界 |
12 | SIGUSR2 | 用户定义信号2 |
13 | SIGPIPE | 向非法管道中写数据 |
14 | SIGALARM | 闹钟警报 |
15 | SIGTERM | 软件中止 |
16 | 。。。 | |
17 | SIGCHLD | 子进程死亡 |
18 | 。。。 |
Linux 的软中断信号在/usr/src/linux-2.4/include/asm/signal.h 中定义。
调用函数说明
预置一个软信号
signal(sig , function)
参数说明:
sig系统给定的软中断中的序号或名称(查表)
function与软中断信号关联的函数名,捕捉到软中断信号后转到该函数执行
发送一个软信号
int kill(pid ,sig)
功能:向pid发送sig
参数说明:
pid表示一个或一组进程的标识号
pid值 | 含义 |
---|---|
>0 | 发送给特定的pid进程 |
=0 | 发送给同组的所有进程 |
=-1 | 发送给同用户标识符的进程 |
sig软中断信号的序号或名称
注意:只能是核心或超级用户进程才能 kill 来向任意的其他进程发送软中断信号,而普
通用户进程只能 kill 向同组或同用户标识的进程发送软中断信号,而不能向任意的其他进程
发送软中断信号。
思路
先使用 signal() 系统调用函数进行预置。预置的目的是将某个软中断信号与某个可执行的处理函数进行关联,当信号发出并被指定的进程接收后,系统就中断接收该软件中断信号进程的执行,转而执行与信号相关联的函数,该函数执行完毕后再返回被中断的进程继续执行。
事实上,除了用户定义信号 SIGUSR1 和 SIGUSR2 外,其他软中断信号都已经由操作系统预置了相应的处理函数,用户进程如果对这些软中断信号进行了预置,则使该信号与新的函数进行关联,当该软中断信号被接收时,转而执行的不再是操作系统预置的处理函数,而是用户对该软中断信号重新预置的处理函数。
对于同一个软中断信号,可以通过多个 signal() 系统调用分别与不同的处理函数进行关联。系统在响应该软中断信号时,执行的是当前预置的处理函数(最近预置的),从而实现同一软中断信号在不同的情况下转向不同的处理函数去执行。
实例
使用软中断实现父子进程间通信
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
int k;
void int_func(int sig) /*中断处理函数*/
{
k=0;
}
main()
{
int p;
int shmid;
char *viraddr;
char buffer[BUFSIZ];
signal(SIGUSR1,int_func); /*预置信号对应的函数*/
k=1;
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while((p=fork())==-1);
if(p==0)
{
while(k==1); /*等待父进程发软中断信号*/
printf("Your message is :\n%s",viraddr);
/*输出共享存储区内容*/
shmdt(viraddr); /*断开共享存储区*/
shmctl(shmid,IPC_RMID,0); /*撤销共享存储区*/
exit(0);
}
else
{
while(1)
{
puts("Enter some text:");
fgets(buffer,BUFSIZ,stdin); /*从stdin中读入输入内容*/
strcat(viraddr,buffer); /*追加到共享存储区*/
if(strncmp(buffer,"end",3)==0)
break;
}
shmdt(viraddr); /*断开共享存储区*/
kill(p,SIGUSR1); /*发送一个中断信号*/
exit(0);
}
}