POSIX定时器:定时器的信号处理程序冻结

这篇文章与以下内容有关: POSIX TIMER-有多个计时器

我想在SignalHandler中调用一个函数。 此函数是TCP套接字客户端(getSpeed)。 每次计时器滴答一秒钟时它从服务器获取数据并发送一个信号,然后调用相应的处理程序。

首先,我不确定从信号处理程序调用函数是否是一个好习惯。

现在问题是,每当我执行与服务器通信的程序时,我的代码就会随机冻结。

如果这种使用信号定义计时器的方式很糟糕(并且可能导致一些隐藏的竞争条件)是否有更好的方法来编码上述场景?

#include  #include  #include  #include  #include  #include  #include  #include  static timer_t tid; static timer_t tid2; void SignalHandler(int, siginfo_t*, void* ); timer_t SetTimer(int, int, int); int getSpeed(void) { int sockFD = 0; struct sockaddr_in addr; int numbytes; unsigned char rxMsg[128]; /* open socket */ if((sockFD = socket(AF_INET, SOCK_STREAM, 0)) <= 0) { fprintf(stderr, "%s: error while creating socket\n", __func__); return -1; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; inet_aton(IP, (struct in_addr *)(&(addr.sin_addr))); addr.sin_port = htons(DATA_PORT); if (connect(sockFD,(struct sockaddr *) &addr,sizeof(addr)) < 0) fprintf(stderr, "%s: failed to connect to server\n", __func__); if((numbytes = recv(sockFD, rxMsg, sizeof(rxMsg), 0)) < 1){ fprintf(stderr, "%s: failed to recv data from vehicle\n", __func__); close(sockFD); return -1; } printf("bytes received from Client is : %d\n", numbytes); printf("Data = %s\n",rxMsg); // close socket close(sockFD); return 0; } int main(int argc, char *argv[]) { 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, 1); 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, 1); for(;;); 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"); getData(); } else if (signo == SIGINT) { timer_delete(tid); timer_delete(tid2); perror("Crtl+c cached!"); exit(1); // exit if CRTL/C is issued } } timer_t SetTimer(int signo, int sec, int mode) { 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); if (mode == 1) { itval.it_interval.tv_sec = itval.it_value.tv_sec; itval.it_interval.tv_nsec = itval.it_value.tv_nsec; } else { itval.it_interval.tv_sec = 0; itval.it_interval.tv_nsec = 0; } if (timer_settime(tid, 0, &itval, &oitval) != 0) { perror("time_settime error!"); } } else { perror("timer_create error!"); return NULL; } return tid; } 

POSIX规范确切地告诉您可以从信号处理程序安全地调用哪些API函数(在2.4.3节末尾附近有一个列表)。

socketconnectrecvclose都在列表中,所以它们应该是安全的。 printffprintf不是,这并不奇怪,因为它们管理用户空间缓冲区,在存在异步信号时很难保持一致。

所以除了printf类型调用之外,这段代码实际上对我来说还不错。 当您的“代码冻结”时,您是否尝试使用调试器附加以查看您遇到的问题?

也就是说,处理这种情况的通常方法是两种方式之一。

第一种方式:如果您的应用程序有“事件循环”,请安排信号只是为了发送一个事件。 然后你的主线程处理该事件就像任何其他事件一样,并且一切都保持良好和同步。

第二种方式:将线程用于周期性任务。 线程可以循环调用sleep(1)并执行周期性任务。

但我仍然认为你的方法应该有效。