异步IO

一些背景知识

异步IO也能解决多路IO的问题。
要结合fcntl和signal来实现。
下面这段从man手册里面摘录下来的描述对理解怎么使用异步IO挺有帮助的,我看完例程之后不怎么懂,然后慢慢查man手册,看完这段就明了很多了。

F_SETOWN (int)
              Set the process ID or process group ID that will receive  SIGIO
              and  SIGURG  signals for events on the file descriptor fd.  The
              target process or process group ID  is  specified  in  arg.   A
              process ID is specified as a positive value; a process group ID
              is specified as a negative value.  Most commonly,  the  calling
              process  specifies  itself as the owner (that is, arg is speci‐
              fied as getpid(2)).
              As well as setting the file descriptor  owner,  one  must  also
              enable  generation  of signals on the file descriptor.  This is
              done by using the fcntl() F_SETFL command to  set  the  O_ASYNC
              file status flag on the file descriptor.  Subsequently, a SIGIO
              signal is sent whenever input or output becomes possible on the
              file  descriptor.   The fcntl() F_SETSIG command can be used to
              obtain delivery of a signal other than SIGIO.

首先 F_SETOWN 是fcntl里面的一个command。它的作用就是用来设置进程的ID或者进程组的ID,这些ID是那些会接收fd上产生的时间的SIGIO信号或者SIGURG信号。查了下SIGURG跟socket有关。
那些目标进程或者进程组的ID是在fcntl原型里面的arg里面指定的。
第一段最后讲到一般调用的进程会把自己设置为那个owner,所以arg用getpid(作用是获取当前进程的进程号)来指定ID号。

第二段说除了设置好fd的owner之后,还要使得这个fd能够产生信号,所以这里就需要通过用fcntl的F_SETFL把O_ASYNC这个flag的状态给fd加上。随后SIGIO就能在输入或者输出的时候发送了。

signal函数的原型


SYNOPSIS
       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

第一个传signum,这里我们要用异步IO,所以设置为SIGIO,当然还有其他很多很多的signum,在man 7 signal里面有定义。

signal()  sets  the disposition of the signal signum to handler, which
       is either SIG_IGN, SIG_DFL, or the  address  of  a  programmer-defined
       function (a "signal handler").

description里面说signal函数就是给信号的signum设置一个处理程序,这个处理程序要么是SIG_IGN,SIG_DFL,要么就是一个程序员定义的一个函数的地址,通常直接把函数名丢进去,因为函数名就是该函数的地址。

还有一段需要注意的。

 *  If the disposition is set to a function, then first either the dis‐
          position is reset to SIG_DFL, or the signal is blocked (see  Porta‐
          bility below), and then handler is called with argument signum.  If
          invocation of the handler caused the signal to be blocked, then the
          signal is unblocked upon return from the handler.

我们这里会调用一个function的,所以要看这一段。
他就说如果是handler设置为一个function的话,开始的时候要么就会重新设置位SIG_DFL,要么就会足额的了,然后就会通过signum的值去调用handler,也就是调用我们的function,如果请求调用的时候引起了信号被阻塞的话,当处理完之后返回的时候就会解除阻塞了。

说了这么一大段,直接上代码

代码

#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

int fd = -1;
// 这个就是我们signum要调用的handler
void func_mouse(int sig)
{
	char mousebuf[120];
	if (sig != SIGIO)
		return;
	
	memset(mousebuf, 0, sizeof(mousebuf));
	read(fd,mousebuf,sizeof(mousebuf));
	printf("what I read is %s\n",mousebuf); 
}

int main(int argc,char* argv[])
{
	int flag = -1;
	char keyboardbuf[120];
	
	//读鼠标的fd
	fd = open("/dev/input/mouse0",O_RDONLY);
	if (fd < 0)
	{
		perror("open:");
		return -1;
	}	
	//这两句就是给原fd加上O_ASYNC的flag
	flag = fcntl(fd,F_GETFL);
	flag = flag|O_ASYNC;
	fcntl(fd,F_SETFL,flag);
	//这里就把当前进程设置为调用异步IO事件的进程,所以用getpid
	fcntl(fd, F_SETOWN, getpid());
	
	//使用signal函数给这个异步IO的signum设置一个handler,
	//就是产生了这个异步IO之后需要什么handler来处理。
	signal(SIGIO, func_mouse);

	
	
	 //读键盘
	while(1)
	{
		memset(keyboardbuf,0,sizeof(keyboardbuf));
		
		read(0,keyboardbuf,5);
		printf("what I read is %s\n",keyboardbuf); 
	}
	
	close(fd); //其实这里close不close都一样
	//因为上面一直while(1)根本下不来,而且最后关掉的时候进程都没了fd也顺带关了
	
	return 0;
}

果然看完课程之后,看完别人的例程代码,还是自己研究一下才会印象深刻。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值