信号方式
软中断信号Signal,简称信号,用来通知进程发生了异步时间。
进程之间可以通过系统调用kill等函数来发送软中断信号,通知进程发生了某个事件,但信号只能用来通知进程发生了什么事件,并不给该进程传递任何数据。
信号是异步的,一个进程不必通过任何操作来等待信号的到达
信号处理的三个过程:发送信号、接收信号、处理信号
信号处理的三种方式:
- 忽略此信号:大多数信号都可以忽略,但是SIGKILL和SIGSTOP不可忽略
- 捕捉信号:通知内核在某种信号发生时,调用用户的函数来处理时间
- 执行系统默认动作:大多数信号的默认动作是终止该进程,可以使用
man 7 signal
查看默认信号。可以使用kill –l(字母l)
列出系统支持的信号 ,其中信号值小于34都是不可靠信号。
一、使用
- 头文件:#include <signal.h>
- 函数原型:void (*signal(int sig, void (*func)(int)))(int),
- 函数返回信号处理程序之前的值,当发生错误时返回 SIG_ERR
- 参数说明
sig:在信号处理程序中作为变量使用的信号码,可自定义
func:一个指向信号处理函数的指针,可自定义
常用的预定义信号处理函数为SIG_DFL,SIG_IGN(忽略此信号)
二、演示程序
1、程序一
Test3-1-2中自定义几个信号处理函数,其中部分是截获后打印信息,程序继续;部分是截获后打印信息,程序退出。
Test3-1-1中定时向test3-1-2发送相应的信号,同时可以通过控制台手工向test3-1-2发送相应的信号。
//test3-1-1
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define SIGPRINT_CONTINUE 34 //自定义信号,大于34的信号量都是未定义的,可使用
#define SIGPRINT_TERM 35
int main()
{
//fork子进程后父进程退出,创建守护进程
pid_t pid1;
pid1=fork();
if(pid1==-1||pid1>0)
return 0;
//获取test3-1-2的pid号
int pid;
FILE *fp = popen("ps -e | grep \'test3-1-2\' | awk \'{print $1}\'","r");
char buffer[10] = {0};
fgets(buffer, 10, fp);
pid=atoi(buffer);
kill(pid,SIGPRINT_CONTINUE); //向test3-1-2发送SIGPRINT_CONTINUE信号
sleep(10);
kill(pid,SIGPRINT_TERM); ////向test3-1-2发送SIGPRINT_TERM信号
while(1)
sleep(1);
}
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SIGPRINT_CONTINUE 34
#define SIGPRINT_TERM 35
/*信号SIGPRINT_CONTINUE的处理函数*/
void print_continue(int sig)
{
printf("\nWARNING! - I got signal %d\n", sig);
printf("I need to print something and continue running!\n");
}
/*信号SIGPRINT_TERM的处理函数*/
void print_term(int sig)
{
printf("\nWARNING! - I got signal %d\n", sig);
printf("End\n");
exit(0);
}
/*相应键盘输出产生的中断的处理函数*/
void replyKeyInput(int sig)
{
printf("\nWARNING - I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DFL);
}
int main()
{
pid_t pid;
pid=fork();
if(pid==-1||pid>0)
return 0;
(void) signal(SIGPRINT_CONTINUE,print_continue);
(void) signal(SIGPRINT_TERM, print_term);
//改变终端中断信号SIGINT的默认行为,使之执行replyKeyInput函数
(void) signal(SIGINT, replyKeyInput);
while(1)
sleep(1);
}
运行结果:
2、程序二
Test3-2-1写文件(此时test3-2-2延时等待)后用自定义的特定信号通知test3-2-2去读,自己变为延时等待状态;
test3-2-2收到此信号后去读文件的内容,读取后清空文件,写入新的内容,再用自定义的特定信号通知3-2-1去读,自己变为演示等待状态。
//test3-2-1
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define SIGFILEREADY 34 //自定义信号量34为文件已准备信号
#define FILE_PATH "myfile"
#define BUFSIZE 50
#define HIS "test3-2-2"
char buffer[BUFSIZE];
int pid=0;
/*信号SIGFILEREADY的处理函数*/
void opFile(int sig)
{
//收到信号表示对方写完成,我方可读取数据
printf("It is test3-2-1 reading file...\n");
FILE *fp=fopen(FILE_PATH,"r+");
fgets(buffer,BUFSIZE,fp);
printf("[Data]:%s\n\n",buffer);
fclose(fp);
sleep(1);
fp=fopen(FILE_PATH,"w+");
fputs("Hello,test3-2-2!These data is writen by test3-2-1!",fp);
fclose(fp);
sleep(1);
//写完成后向对方发送SIGFILEREADY信号
kill(pid,SIGFILEREADY);
}
int main()
{
//fork子进程后父进程退出,创建守护进程
pid_t pid1;
pid1=fork();
if(pid1==-1||pid1>0)
return 0;
FILE *fp=fopen(FILE_PATH,"w+");
fputs("Hello,test3-2-2!These data is writen by test3-2-1!",fp);
fclose(fp);
sleep(1);
fp=fopen(FILE_PATH,"r+");
fgets(buffer,BUFSIZE,fp);
printf("INIT DATA:%s\n",buffer);
fclose(fp);
sleep(1);
while(pid<=0)
{
//获取test3-2-2的pid号
FILE *fp = popen("ps -e | grep \'test3-2-2\' | awk \'{print $1}\'","r");
char buf[10] = {0};
fgets(buf, 10, fp);
pid=atoi(buf);
}
sleep(1);
(void)signal(SIGFILEREADY,opFile);
kill(pid,SIGFILEREADY);
while(1)
sleep(1);
}
//test3-2-2
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define SIGFILEREADY 34 //自定义信号量34为文件已准备信号
#define FILE_PATH "myfile"
#define BUFSIZE 50
#define HIS "test3-2-1"
char buf[BUFSIZE];
int pid=0;
/*信号SIGFILEREADY的处理函数*/
void opFile(int sig)
{
printf("It is test3-2-2 reading file...\n");
FILE *fp=fopen(FILE_PATH,"r+");
fgets(buf,BUFSIZE,fp);
printf("[Data]:%s\n\n",buf);
fclose(fp);
sleep(1);
fp=fopen(FILE_PATH,"w+");
fputs("Hello,test3-2-1!These data is writen by test3-2-2!",fp);
fclose(fp);
sleep(1);
kill(pid,SIGFILEREADY);
}
int main()
{
//fork子进程后父进程退出,创建守护进程
pid_t pid1;
pid1=fork();
if(pid1==-1||pid1>0)
return 0;
while(pid<=0)
{
//获取test3-2-1的pid号
FILE *fp = popen("ps -e | grep \'test3-2-1\' | awk \'{print $1}\'","r");
char buf[10] = {0};
fgets(buf, 10, fp);
pid=atoi(buf);
}
(void)signal(SIGFILEREADY,opFile);
while(1)
sleep(1);
}
运行结果: