2012-04-10 114 views
2

我想在代碼中實現計時器,我發現的所有示例都使用while(1)for(;;),但是當我嘗試使用scanf我的程序終止。它是否在stdin上有任何價值,因爲如果我使用scanf兩次,則在從程序退出之前調用兩次定時器。 這裏是我的示例代碼:程序終止,如果我使用scanf

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <signal.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <time.h> 

#include <linux/socket.h> 
#include <time.h> 


#define SIGTIMER (SIGRTMAX) 
#define SIG SIGUSR1 
static timer_t  tid; 
static timer_t  tid2; 

void SignalHandler(int, siginfo_t*, void*); 
timer_t SetTimer(int, int); 

int main(int argc, char *argv[]) { 

    int t; 

    printf("SIGRTMAX %d\n", SIGRTMAX); 
     printf("SIGRTMIN %d\n", SIGRTMIN); 

    struct sigaction sigact; 
    sigemptyset(&sigact.sa_mask); 
    sigact.sa_flags = SA_SIGINFO; 
    sigact.sa_sigaction = SignalHandler; 
    // set up sigaction to catch signal 
    if (sigaction(SIGTIMER, &sigact, NULL) == -1) { 
     perror("sigaction failed"); 
     exit(EXIT_FAILURE); 
    } 

    // Establish a handler to catch CTRL+c and use it for exiting. 
    sigaction(SIGINT, &sigact, NULL); 
    tid=SetTimer(SIGTIMER, 1000); 

    struct sigaction sa; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_SIGINFO; 
    sa.sa_sigaction = SignalHandler; 
    // set up sigaction to catch signal 
    if (sigaction(SIG, &sa, NULL) == -1) { 
     perror("sa failed"); 
     exit(EXIT_FAILURE); 
    } 

    // Establish a handler to catch CTRL+c and use it for exiting. 
    sigaction(SIGINT, &sa, NULL); 
    tid2=SetTimer(SIG, 1000); 

    // for(;;); or while(1) Working properly 

    scanf("%d", &t); /// Program terminates 
    return 0; 
} 

void SignalHandler(int signo, siginfo_t* info, void* context) 
{ 


    if (signo == SIGTIMER) { 
     printf("Command Caller has ticked\n"); 

    }else if (signo == SIG) { 
     printf("Data Caller has ticked\n"); 

    } else if (signo == SIGINT) { 
     timer_delete(tid); 
     perror("Crtl+c cached!"); 
     exit(1); // exit if CRTL/C is issued 
    } 
} 
timer_t SetTimer(int signo, int sec) 
{ 
    static struct sigevent sigev; 
    static timer_t tid; 
    static struct itimerspec itval; 
    static struct itimerspec oitval; 

    // Create the POSIX timer to generate signo 
    sigev.sigev_notify = SIGEV_SIGNAL; 
    sigev.sigev_signo = signo; 
    sigev.sigev_value.sival_ptr = &tid; 

    if (timer_create(CLOCK_REALTIME, &sigev, &tid) == 0) 
    { 

     itval.it_value.tv_sec = sec/1000; 
     itval.it_value.tv_nsec = (long)(sec % 1000) * (1000000L); 
     itval.it_interval.tv_sec = itval.it_value.tv_sec; 
     itval.it_interval.tv_nsec = itval.it_value.tv_nsec; 



     if (timer_settime(tid, 0, &itval, &oitval) != 0) 
     { 
      perror("time_settime error!"); 
     } 
    } 
    else 
    { 
     perror("timer_create error!"); 
     return NULL; 
    } 
    return tid; 
} 

所以,我怎樣才能解決這個問題呢? 任何幫助將被讚賞。 謝謝,Yuvi

+1

C或C++? (填充使SO很高興) – pmg 2012-04-10 10:11:53

+0

看起來像C,@pmg – 2012-04-10 10:14:01

+0

我認爲信號是相同的C&C++ AFAIK – Yuvi 2012-04-10 10:23:21

回答

4

信號中斷scanf。如果之後添加perror('scanf') scanf函數輸出將是:

 
SIGRTMAX 64 
SIGRTMIN 34 
Command Caller has ticked 
Data Caller has ticked 
scanf: Interrupted system call 

如果您要更換scanf有:當它失敗Interrupted system call

 
do { 
    errno = 0; 
    scanf("%d", &t); 
} while(errno == EINTR); 

scanf函數將重試。

2

絕對不能在信號處理程序中使用printfperror。它們不可重入。

另外,如果您的程序在其中收到信號,則有可能返回錯誤scanf。如果scanf返回EOF,則檢查errno,它可能是EINTR

+1

我知道這些函數不是'異步安全的',這只是一個示例代碼來理解功能:) – Yuvi 2012-04-10 10:44:53