Linux使用O_ASYNC实现异步IO

本文探讨一个《Unix/Linux编程实践教程》P219出现的bug,在Linux上bounce_async.c程序代码运行失败。

Unix有两个异步输入(asynchronous input)系统。

一种方法是当输入就绪时发送信号,另一个系统当输入被读入时发送信号。UCB(BSD)中通过设置文件描述块(file descriptor)的O_ASYNC位来实现第一种方法。

第二种方法是POSIX标准,它调用aio_read。

实验第一种方法时,我采用书中代码,就是一个弹球程序,发现了其不能在键入"Q"正常退出

  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <curses.h>   
  4. #include <signal.h>   
  5. #include <fcntl.h>   
  6.   
  7. #define MESSAGE "hello"   
  8. #define BLANK   "     "   
  9.   
  10. int row =10;  
  11. int col =0;  
  12. int dir =1;  
  13. int delay =200;  
  14. int done =0;  
  15.   
  16.   
  17. int main()  
  18. {  
  19.     void on_alarm(int);  
  20.     void on_input(int);  
  21.     void enable_kbd_signals();  
  22.   
  23.     sigset_t * set;  
  24.     set=(sigset_t*)malloc(sizeof(set));  
  25.     sigemptyset(set);  
  26.     sigaddset(set,SIGIO);  
  27.     sigprocmask(SIG_UNBLOCK, set, NULL);  
  28.   
  29.     initscr();  
  30.     crmode();  
  31.     noecho();  
  32.     clear();  
  33.   
  34.     enable_kbd_signals();  
  35.     signal(SIGIO,(on_input));  
  36.     enable_kbd_signals();  
  37.     signal(SIGALRM,on_alarm);  
  38.     set_ticker(delay);  
  39.   
  40.     move(row,col);  
  41.     addstr(MESSAGE);  
  42.   
  43.     while(!done)  
  44.     {  
  45.   
  46.         pause();  
  47.   
  48.     }  
  49.     endwin();  
  50. }  
  51.   
  52. void on_input(int signum)  
  53. {  
  54.     int c = getch();  
  55.     if(c=='Q'||c==EOF)  
  56.         done=1;  
  57.     else if(c==' ')  
  58.         dir=-dir;  
  59.   
  60. }  
  61.   
  62. void on_alarm(int signum)  
  63. {  
  64.     signal(SIGALRM,on_alarm);  
  65.     mvaddstr(row,col,BLANK);  
  66.     col+=dir;  
  67.     mvaddstr(row,col,MESSAGE);  
  68.     refresh();  
  69.   
  70.     if(dir==-1&&col<=0)  
  71.         dir=1;  
  72.     else if(dir==1&&col+strlen(MESSAGE)>=COLS)  
  73.         dir=-1;  
  74. }  
  75.   
  76. void enable_kbd_signals()  
  77. {  
  78.     int fd_flags;  
  79.   
  80.     fcntl(0,F_SETOWN,getpid());  
  81.     fd_flags=fcntl(0,F_GETFL);  
  82.     fcntl(0,F_SETFL,(fd_flags|O_ASYNC));  
  83. }  
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <fcntl.h>

#define MESSAGE "hello"
#define BLANK	"     "

int row	=10;
int col =0;
int dir =1;
int delay =200;
int done =0;


int main()
{
	void on_alarm(int);
	void on_input(int);
	void enable_kbd_signals();

	sigset_t * set;
	set=(sigset_t*)malloc(sizeof(set));
	sigemptyset(set);
	sigaddset(set,SIGIO);
	sigprocmask(SIG_UNBLOCK, set, NULL);

	initscr();
	crmode();
	noecho();
	clear();

	enable_kbd_signals();
	signal(SIGIO,(on_input));
	enable_kbd_signals();
	signal(SIGALRM,on_alarm);
	set_ticker(delay);

	move(row,col);
	addstr(MESSAGE);

	while(!done)
	{

		pause();

	}
	endwin();
}

void on_input(int signum)
{
	int c = getch();
	if(c=='Q'||c==EOF)
		done=1;
	else if(c==' ')
		dir=-dir;

}

void on_alarm(int signum)
{
	signal(SIGALRM,on_alarm);
	mvaddstr(row,col,BLANK);
	col+=dir;
	mvaddstr(row,col,MESSAGE);
	refresh();

	if(dir==-1&&col<=0)
		dir=1;
	else if(dir==1&&col+strlen(MESSAGE)>=COLS)
		dir=-1;
}

void enable_kbd_signals()
{
	int fd_flags;

	fcntl(0,F_SETOWN,getpid());
	fd_flags=fcntl(0,F_GETFL);
	fcntl(0,F_SETFL,(fd_flags|O_ASYNC));
}


遇到这个问题后,我很困惑,于是邮件问了作者Bruce Molay,没想到他神速的回复了我的邮件!兴奋异常!

下面我贴出的回复,这不算侵权吧,@Bruce Molay~


bmolay@gmail.com
Dear Scott,

Thank you for writing.  The reason that 'Q' does not get you out of the program
is that on this version of Linux (and on most, I think) the signal handler is called,
the 'Q' is read, the done variable is set but the program never returns from pause().

Which is silly as pause is supposed to block until a signal is handled.

One solution is to change the on_input() function to call endwin and exit if the input
is 'Q' or EOF.

        if ( c == 'Q' || c == EOF ){
                done = 1;
                move(LINES-1,0);
                endwin();
                exit(0);
        }

I checked it, and pause returns once, but never returns again.  The signal
handlers are called and processed but pause does not return.

Try the aio one.  that one works.  I think async version is not supported
on Linux very well.

     他的英文还是很好懂的。真是很大家风范,大家以后遇到问题也可以多联系作者,It is so cool!!

Linux和Unix有一定的区别,在学习Unix的过程中,我们经常使用Linux做实验,我们需要注意其区别!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值