2011-04-09 159 views
0

我们当前的项目基于通过包括滚动来扩展more。为此,定时器间隔必须设置一段时间。我不确定的部分是报警信号的回路应该在哪里。我见过的所有例子都有主值中的定时器值,然后通过无限循环中的pause()明确调用信号处理程序。带间隔计时器的故障

我的代码是有点不同,因为功能性要求去像

print first screen of text after getting terminal dimensions 
print prompt 
    if prompt = space, print another screen of text //WORKS 
    if prompe = q, restore original terminal settings & quit program //WORKS 
    if prompt = ENTER, initialize scroll at 1 line every 2 seconds //DOESN'T WORK 
    if prompt == f/s, increase/decrease scroll speed by 20% //DOESN'T WORK 

读缓冲区,文件指针和itimerval结构都是全局变量,以避免将作为参数通过功能链。

该方案的主要功能是

void processInput(FILE *fp){ 
    void printLine(int); //prints a single line of text 
    signal(SIGPROF, printLine); 
    int c; 

    //print first screen of text, check for more text to display 

    info(); //print prompt at bottom of screen 
    FILE *fterm= fopen("/dev/tty", "r"); 

    while ((c=getc(fterm)) != EOF){ 
    if (c== '\n'){ 
     setTimer(2); 

    //four more conditionals like this in basic similarity 

    } 
} 

我SetTimer函数具有2秒的间隔基,和改变通过加/减基于从用户F/S输入的20%。

void setTimer(int direction){ 
    int speed=2000000; //2 seconds 
    int change= 400000; //400 milliseconds, 20% of 2 seconds 
    if (direction == 1) //slow down by 20% 
    speed+= change; 
    if (direction == 0) 
    speed -= change; 

    timer.it_value.tv_sec=2; 
    timer.it_value.tv_usec=0; 
    timer.it_interval.tv_sec=0; 
    timer.it_interval.tv_usec= speed; 

    setitimer(ITIMER_PROF, &timer, NULL); 

} 

第一个问题:我应该使用SIGALRM VS SIGPROF,并相应地改变ITIMER_XXXX变量?

其次,我应该在哪里放置回路来触发信号?我试过

while(1) 
    pause(); 

在几个条件中,但它具有停止执行和忽略任何输入的效果。

回答

1

不知道您的要求的细节,难道你不能更容易地使用 select()

将您的初始选择超时设置为2秒,并根据f/s输入进行调整,同时如果在处理超时之前有任何标准输入。

或多或少有效的大致轮廓:

int retval; 
fd_set rfds; 

int input = fileno(fterm); 

struct timeval tv, delay; 

delay.tv_sec = 2; 
delay.tv_usec = 0; 

while (true) 
{ 
    FD_ZERO(&rfds); 
    FD_SET(input, &rfds); 

    tv.tv_sec = delay.tv_sec; 
    tv.tv_usec = delay.tv_usec; 

    retval = select(input + 1, &rfds, NULL, NULL, &tv); 

    if (retval == -1) 
     perror("select()"); 
    else 
     if (retval) 
     { 
      if (FD_ISSET(input, &rfds)) 
      { 
       command = readInput(...); 

       switch(command) 
       { 
        case 'q' ... cleanup & quit 
        case 's' ... calc 20% off delay values 
        case etc ... 
        case default...error handling 
       } 
      } 
     } 
     else //timeout 
      printLine(); 
} 
1

pause()工作是危险的,因为它不是一个原子操作...你的程序可以由OS中断造成“丢失”的到来信号。此外,当pause()本身因为信号的到来而返回时,它将再次简单地呼叫pause()。这意味着你将不得不在信号处理器内部完成所有工作,这可能不是最好的,也就是说,如果你在信号处理器内部,当下一个信号熄灭时,你最终可能会一些不可预知的行为,如果你还没有计划过这样的事件。

更好的方法是,请执行下列操作:

1)安装信号屏蔽,阻止在程序开始SIGPROF。
2)使用sigwait(),而不是使用信号处理程序来完成您的繁重工作,并使用包含SIGPROF掩码的sigset_t进行设置。
3)安装程序的主流方式如下:

sigset_t sigset; 
sigemptyset(&sigset); 
sigaddset(&sigset, SIGPROF); 
sigprocmask(SIG_BLOCK, &sigset, NULL); //block the SIGPROF signal 

//process your input 

//if you need to, initialize your timer and set it to go off 

while(SOME_FLAG_IS_TRUE) //maybe this loops forever ... depends on what you want? 
{ 
    sigwait(&sigset, &signal_num); 

    if (signal_num != SIGPROF) 
     continue; 

    //process input ... 

    //... setup new interval timer with correct timeout ... 

    //... repeat loop and/or exit loop or set flag to exit loop 
} 

,应始终从间隔定时器捕捉信号,因为调用sigwait()等待信号到达您的过程之后将正常返回,并且SIGPROF信号始终被阻止,这意味着您不能“丢失”信号......相反,至少其中一个信号将排队等待下一次致电sigwait()的呼叫,以防万一到达时在你的while循环中处理一些东西。

希望这有助于

杰森