本文探讨一个《Unix/Linux编程实践教程》P219出现的bug,在Linux上bounce_async.c程序代码运行失败。
Unix有两个异步输入(asynchronous input)系统。
一种方法是当输入就绪时发送信号,另一个系统当输入被读入时发送信号。UCB(BSD)中通过设置文件描述块(file descriptor)的O_ASYNC位来实现第一种方法。
第二种方法是POSIX标准,它调用aio_read。
实验第一种方法时,我采用书中代码,就是一个弹球程序,发现了其不能在键入"Q"正常退出
- #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~
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做实验,我们需要注意其区别