注:此篇文章着重讲述signal的使用框架,至于文章中涉及的fcntl的具体使用方法请移步https://www.cnblogs.com/zxc2man/p/7649240.html
异步IO:操作系统使用软件实现一套中断响应系统
工作方式:当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常的处理自己的事情,当异步事件发生之后当前进程会收到一个SIGIO信号,从而执行绑定的处理函数,进而处理这个异步事件。
涉及的函数:fcntl F_GETFL F_SETFL O_ASYNC F_SETOWN
代码实现的功能:将一个事件(鼠标的输入)注册为我们的异步通知任务,另一个(键盘的输入)设置为我们的主任务,当异步任务的有信号传来时就进行异步注册函数的执行。
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
char buff[20];
int mousefd=-1;
int ret=-1;
int flag=0;
/* 在函数内处理异步通知事件*/
void func(int sig)
{
if(sig!=SIGIO)
{
return;
}
else
{
printf("sig={ %d } .\n",sig);
memset(buff,0,sizeof(buff));
ret=read(mousefd,buff,10);
if(ret>0)
{
printf("mouse data is { %s } .\n",buff);
}
else
{
perror("read .\n");
}
}
}
int main(void)
{
mousefd=open("/dev/input/mouse0",O_RDWR);
if(mousefd<0)
{
perror("open mousefd");
}
// 将鼠标的文件描述符设置为可以接受异步IO
flag=fcntl(mousefd,F_GETFL); //获得mousefd文件描述符的标志位
flag |=O_ASYNC; //设置flag,当I/O可用的时候,允许SIGIO信号发送到进程组
fcntl(mousefd,F_SETFL,flag); //设置鼠标的文件描述符mousefd为flag特性的
//将异步IO事件的接收进程设置为当前进程
fcntl(mousefd,F_SETOWN,getpid());
//注册当前进程的SIGIO信号捕捉函数
signal(SIGIO,func);
while(1)
{
read(0,buff,10);
printf("jianpan data is { %s } .\n",buff);
}
}
值得一提的signal是一个抽象函数,在func(int)函数内传入的参数,大家可能觉得他有点莫名其妙,其实他的赋值是有缘由的。
signal函数定义为: void (*signal(int, void (*func)(int)))(int);
1. signal函数原型说明此函数需要两个参数,
返回一个函数指针,而这个指针指向的函数无返回值(void)。
第一个参数signo是一个整数,
第二个参数是函数指针,它所指向的函数需要一个整型参数,无返回值。
signal的返回值是一个函数地址,该函数有一个整型参数(即最后的(int))。
用自然语言来描述也就是要向信号处理程序(func) 传送一个整型参数,无返回值。
当调用signal设置信号处理程序时,第二个参数是指向该函数(也就是信号 处理程序)的指针。signal的返回值则是指向之前的信号处理程序的指针。
关于signal函数最后的(int),其实简单的说就是因为signal返回了一个函数指针,这个函数指针有一个(int)型参数(即void (*func)(int)中的int),这两个值应该是保持一致的。
如果signal函数不是返回的函数指针,那么我们的抽象函数可以定义为如下形式:int ( *test)(....)这样的形式。
或者如果指向的函数没有参数(即void),我们也可以写为: int *(* test)(void),这样的形式。
也就是说signal函数自身被调用之后会返回一个函数地址,这个函数地址对应的函数是一个有int型参数(设其为a)的函数,而这个int型的参数(a)和我们在signal函数内传入的第二个参数(待处理的事件函数func)内的参数(sig)的值是保持一致的,即a=sig 。 然后在func(int)函数就和我们的SIGIO联系起来了,通过判断sig和SIGIO的关系来确定我们异步处理信号是否来临,是否执行异步处理函数。
注:键盘为标准的输入,其对应的文件描述符为0;
鼠标对应的文件在/dev/input内,可利用 cat mouse* 的方式,进行鼠标对应文件的的测试
如:输入cat mouse0 然后晃动鼠标,会有信息打印,cat mouse1或者mouse2后不会有信息的打印