linux中实现对输入的异步
1:传统的输入信号
传统的输入都是通过阻塞来实现,例如getchar一直等待用户输入。又或者是再curses库中的getch都是通过阻塞的方式来等待用户输入。那么想象一个场景要设计一个游戏,这个游戏可以让玩家动态输入一些值来动态调整游戏参数。不可能通过getchar这样的阻塞函数来获取用户输入把。那么这个该如何实现呢,再想象一下另外一种场景操作系统的CPU不可能是一直等待网卡的输入把。所以对于一些特别的场景阻塞输入是无法满足要求的。下面的这个例子就是一个阻塞输入的例子。
#include<stdio.h> #include<stdlib.h> #include<curses.h> void init_setup ( ); void init_end ( ); void on_input ( ); void do_main ( ); int main ( int argc, char *argv[] ) { init_setup(); on_input(); do_main(); init_end(); return EXIT_SUCCESS; } /* ---------- end of function main ---------- */ void init_setup ( ) { initscr(); crmode(); noecho(); clear(); } /* ----- end of function init_setup ----- */ void init_end ( ) { endwin(); } /* ----- end of function init_end ----- */ void on_input ( ) { char c; while((c = getch()) != ‘q‘){ if(c == ‘w‘) mvaddch(20,20,‘!‘); else if(c == ‘e‘) mvaddch(20,20,‘0‘); else if(c == ‘r‘) mvaddch(20,20,‘t‘); } } /* ----- end of function on_input ----- */ void do_main ( ) { while(1){ move(50,50); addstr("do other thing"); } } /* ----- end of function do_main ----- */
从这个例子可以发现do_main没有执行,因为on_input一直等待用户输入阻塞了下面的程序运行。所以在有些场景像getchar或者getch这类的阻塞函数无法满足一些需求,那么就需要使用异步IO。异步IO的实现有两种方法:
1.设置输入O_ASYNC位
2.使用aio_read()
2:异步输入一
步骤如下:
1.设置0描述符,当输入就绪的时候发送信号
2.设置0描述符O_ASYNC标志位
2.设置信号处理函数。
下面是一个例子:
#include<stdio.h> #include<stdlib.h> #include<curses.h> #include<signal.h> #include<fcntl.h> void init_setup ( ); void init_end ( ); void on_input ( ); void do_main ( ); void enable_kdb_signals(); int main ( int argc, char *argv[] ) { init_setup(); enable_kdb_signals(); signal(SIGIO,on_input); do_main(); init_end(); return EXIT_SUCCESS; } /* ---------- end of function main ---------- */ void init_setup ( ) { initscr(); crmode(); noecho(); clear(); } /* ----- end of function init_setup ----- */ void init_end ( ) { endwin(); } /* ----- end of function init_end ----- */ void on_input ( ) { char c; c = getch(); if(c == ‘w‘) mvaddch(20,20,‘!‘); else if(c == ‘e‘) mvaddch(20,20,‘0‘); else if(c == ‘r‘) mvaddch(20,20,‘t‘); } /* ----- end of function on_input ----- */ void do_main ( ) { while(1){ sleep(1); move(50,50); addstr("do other thing"); refresh(); } } /* ----- end of function do_main ----- */ //设置输入时发送信号,设置输入为O_ASYNC void enable_kdb_signals() { int fd_flags; fcntl(0,F_SETOWN,getpid()); fd_flags = fcntl(0,F_GETFL); fcntl(0,F_SETFL,(fd_flags|O_ASYNC)); }
上面这个例子可以看到do other thing以及输出,do_main正在运行,但是此时你输入字符程序可以通过信号处理函数on_input来接受输入进行响应。达到了异步的效果。
3:异步输入二
异步输入的第二种方法是通过aio_read来实现的,使用aio_read更加灵活,但是设置起来也比较复杂。
设置步骤如下:
1.设置信号处理函数,接受用户输入
2.设置aiocb结构体中的变量指明等待什么类型的输入,当输入的时候产生什么信号。
3.将aiocb结构体传递给aio_read来递交读入请求。
aiocb结构体定义如下:
struct aiocb { /* The order of these fields is implementation-dependent */ int aio_fildes; /* File descriptor */ off_t aio_offset; /* File offset */ volatile void *aio_buf; /* Location of buffer */ size_t aio_nbytes; /* Length of transfer */ int aio_reqprio; /* Request priority */ struct sigevent aio_sigevent; /* Notification method */ int aio_lio_opcode; /* Operation to be performed; lio_listio() only */ /* Various implementation-internal fields not shown */ }; struct sigevent { int sigev_notify; /* Notification method */ int sigev_signo; /* Notification signal */ union sigval sigev_value; /* Data passed with notification */ void (*sigev_notify_function) (union sigval); /* Function used for thread notification (SIGEV_THREAD) */ void *sigev_notify_attributes; /* Attributes for notification thread (SIGEV_THREAD) */ pid_t sigev_notify_thread_id; /* ID of thread to signal (SIGEV_THREAD_ID) */ };
下面是一个简单的例子:
#include<stdio.h> #include<stdlib.h> #include<curses.h> #include<signal.h> #include<fcntl.h> #include<aio.h> void init_setup ( ); void init_end ( ); void on_input ( ); void do_main ( ); void setup_aio_buffer(); struct aiocb kbcbuf; int main ( int argc, char *argv[] ) { init_setup(); signal(SIGIO,on_input); setup_aio_buffer(); aio_read(&kbcbuf); do_main(); init_end(); return EXIT_SUCCESS; } /* ---------- end of function main ---------- */ void init_setup ( ) { initscr(); crmode(); noecho(); clear(); } /* ----- end of function init_setup ----- */ void init_end ( ) { endwin(); } /* ----- end of function init_end ----- */ void on_input ( ) { char c; char *cp = (char *)kbcbuf.aio_buf; if(aio_error(&kbcbuf) != 0) perror("reading faild"); else if(aio_return(&kbcbuf) ==1){ c = *cp; if(c == ‘w‘) mvaddch(20,20,‘!‘); else if(c == ‘e‘) mvaddch(20,20,‘0‘); else if(c == ‘r‘) mvaddch(20,20,‘t‘); } aio_read(&kbcbuf); } /* ----- end of function on_input ----- */ void do_main ( ) { while(1){ sleep(1); move(50,50); addstr("do other thing"); refresh(); } } /* ----- end of function do_main ----- */ void setup_aio_buffer() { static char input[1]; kbcbuf.aio_fildes = 0; #设置接受输入的buf kbcbuf.aio_buf = input; #设置接受输入的字节大小 kbcbuf.aio_nbytes = 1; kbcbuf.aio_offset = 0; #设置处理输入的方法 #SIGE_SIGNAL 代表通过发送信号来处理 kbcbuf.aio_sigevent.sigev_notify =SIGEV_SIGNAL; #设置要发送的信号 kbcbuf.aio_sigevent.sigev_signo = SIGIO; }
本文出自 “专注linux” 博客,请务必保留此出处http://forlinux.blog.51cto.com/8001278/1533448
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。