这篇文章与以下内容有关: POSIX TIMER- Have multiple timers
我想在SignalHandler中调用一个函数。此函数是TCP套接字客户端(getSpeed)。每次计时器滴答一秒钟时它从服务器获取数据并发送一个信号,然后调用相应的处理程序。
首先,我不确定从信号处理程序调用函数是否是一个好习惯。
现在的问题是,每当我执行与服务器通信的程序时,我的代码会随机冻结。
如果这种使用信号定义定时器的方式不好(并且可能导致一些隐藏的竞争条件)是否有更好的方法来编码上述场景?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <linux/socket.h>
#include <time.h>
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;
}
答案 0 :(得分:2)
POSIX spec确切地告诉您可以从信号处理程序安全调用的API函数(在2.4.3节末尾附近有一个列表)。
socket
,connect
,recv
和close
都在列表中,因此它们应该是安全的。 printf
和fprintf
不是,这并不奇怪,因为他们管理用户空间缓冲区,在存在异步信号时很难保持一致。
除了printf
类型调用之外,这段代码实际上对我来说还不错。当你的“代码冻结”时,你是否尝试使用调试器来查看你被困的位置?
那就是说,处理这种情况的常用方法有两种。
第一种方式:如果您的应用程序有“事件循环”,请安排信号只是为了发送一个事件。然后你的主线程处理该事件就像任何其他事件一样,并且一切都保持良好和同步。
第二种方式:将线程用于周期性任务。线程可以循环调用sleep(1)并执行定期任务。
但我仍然认为你的方法应该有效。