2011-04-09 77 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循環中處理一些東西。

希望這有助於

傑森