#include <curses.h> #include <signal.h> #include <sys/time.h> #include <unistd.h> #include <fcntl.h> #define MESG "xxxxxxx"#define BLANK " " #define COLUMS 100 int settimer(int); void move_(int); void keyboard(int); int x = 80; int y = 0; int dir = -1; int ppp = 0; int main(void) { int flag; struct itimerval old; initscr(); crmode(); noecho(); clear(); signal(SIGIO, keyboard); fcntl(0, F_SETOWN, getpid()); flag = fcntl(0, F_GETFL); fcntl(0, F_SETFL, (flag | O_ASYNC)); signal(SIGALRM, move_); settimer(150); mvaddstr(y, x, MESG); refresh(); while(1){ sleep(1); getitimer(ITIMER_REAL, &old); //printf("P %d %d %d %d\n", (int)old.it_value.tv_sec, (int)old.it_value.tv_usec, (int)old.it_interval.tv_sec, (int)old.it_interval.tv_usec); if (ppp == 1) { signal(SIGALRM, SIG_IGN); ppp = 0; } if (ppp == 2) { settimer(150); signal(SIGALRM, move_); ppp = 0; } } endwin(); } int settimer(int msec) { struct itimerval time_val; long sec, usec; sec = msec/1000; usec = (msec%1000) * 1000L; time_val.it_interval.tv_sec = sec; time_val.it_interval.tv_usec = usec; time_val.it_value.tv_sec = sec; time_val.it_value.tv_usec = usec; return setitimer(ITIMER_REAL, &time_val, NULL); } void move_(int signum) { signal(SIGALRM, SIG_IGN); mvaddstr(y, x, BLANK); if (dir == -1 && y == 0) dir =1; if (dir == 1 && y == LINES - 1) dir = -1; y += dir; mvaddstr(y, x, MESG); refresh(); signal(SIGALRM, move_); } void keyboard(int signum) { int c;c = getch();if (c == ' ') dir = -dir;if (c == 'p') ppp = 1;if (c == 'c') ppp = 2; }
程序描述:
程序包括定时器中断和输入终端,来实现一串字符串在屏蔽上移动。
定时器中断:特定时间间隔使字符串在屏幕上移动一定位置。
输入中断:使用户不必阻塞在接收输入字符上,一旦有输入到来,触发输入中断。根据不同输入字符改变字符串运行状态。
问题描述:
1、为防止在处理定时器中断时,新的定时器中断到来,在进入定时器处理函数时,忽略了定时器信号,在定时器处理函数退出时,重新设置捕捉该信号。此处重新捕捉信号不需要重新设置setitimer函数。
2、当输入中断的字符为‘p’,暂停程序,内部实现为忽略定时器信号,当重新输入‘c’字符时,继续捕捉信号,程序继续运行。此时需要重新设置setitimer函数,否则定时器无法触发。
以上两种情况,同为先忽略定时器信号,再捕捉定时器信号,一种需要设置setitimer函数,一种则不需要设置。导致这种差异的原因是什么呢。
经过反复测试:在主函数中调用getitimer函数,获取定时器的值。
发现:
(定时器由it_value,it_interval两部分组成,it_value用于记录下次中断到来时间,随着时间减小;it_interval用于在it_value减为0时,重置it_value,记录两次中断之间的间隔)
当设置定时器后(设置it_value, it_interval),it_value将由指定值减为0,此时若信号为忽略,in_interval将不再继续重置it_value函数。此时it_value 为0, it_interval不为0。
此时定时器处于一种disable状态,但此disable状态与it_value 为0, it_interval为0的关闭状态并不是一个状态。(此处与定时器的manpage略有出入),disable状态不再触发定时器信号。
在上面的例子中,情况1,由于在中断处理函数中先屏蔽再捕捉,基本不会导致在此过程中it_value减为0,(时间太短,不过也有可能,极偶发事件),所以当重新设置捕捉信号时,it_value不是0, 当it_value再次为0时,信号将继续被捕捉,所以此时不需要设置setitimer函数。
情况2,当我们键入‘p’,忽略定时器中断,当我们在键入‘c’,由于键入的时间间隔较长,在这个过程中,定时器的it_value已经减为0,而当减为0时,信号为忽略状态,此时信号将继续处于disbale状态。之后再捕捉,由于定时器将保持disbale状态,将不会触发定时器信号,只有重新设置setitimer函数,重新打开定时器才能触发定时器中断。
以上结论均属于个人推测,未找到相关书籍证实,而且结论与定时器介绍略有偏差,所以还需进一步求证。
为保险起见,建议一旦先忽略,再捕捉定时器信号,均再次设置setitimer函数。