2012-04-10 67 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