linux的异步IO——使用signal实现中断

注:此篇文章着重讲述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后不会有信息的打印

标题

猜你喜欢

转载自blog.csdn.net/qq_41464499/article/details/88018327