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;
}
转载于:https://blog.51cto.com/forlinux/1533448