POSIX计时器:计时器冻结的信号处理程序 [英] POSIX Timer : Signal Handler for Timer freezes

查看:93
本文介绍了POSIX计时器:计时器冻结的信号处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此帖子与以下内容有关: POSIX计时器-具有多个计时器

This post is related to: POSIX TIMER- Have multiple timers

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

I want to call a function in the SignalHandler. This function is a TCP socket client(getSpeed). It gets data from a server every time the timer ticks one second and sends a signal which then calls the corresponding handler.

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

First of all I am not sure if it is good practise to call a function from a signal handler.

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

Now the problem is, my code freezes randomly whenever I execute this program which talks to a server.

如果使用信号定义计时器的方法不好(可能会导致某些隐藏的竞争条件),那么是否有更好的方法来编码上述情况?

If this way of defining a timer using signals is bad(and probably causes some hidden race condition) is there a better way to code the above scenario?

#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;
}

推荐答案

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

The POSIX spec tells you exactly what API functions you may safely call from a signal handler (there is a list near the end of section 2.4.3).

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

socket, connect, recv, and close are all on the list, so they should be safe. printf and fprintf are not, which is not surprising since they manage a user-space buffer, which is hard to keep consistent in the presence of async signals.

因此,除了printf类型调用之外,此代码对我而言实际上看起来还可以.当代码冻结"时,您是否尝试过附加调试器以查看卡在哪里?

So other than the printf type calls, this code actually looks OK to me. When your "code freezes", have you tried attaching with a debugger to see where you are stuck?

也就是说,处理此问题的常用方法是两种方法之一.

That said, the usual way to handle this is one of two ways.

第一种方法:如果您的应用程序具有事件循环",则只需将信号安排为发送事件即可.然后,您的主线程便会像处理其他事件一样处理该事件,并且一切都保持良好且同步.

First way: If your application has an "event loop", arrange for the signal simply to send an event. Then your main thread handles that event just like any other, and everything stays nice and synchronous.

第二种方式:将线程分配给定期任务.该线程可以循环调用sleep(1)并执行您的定期任务.

Second way: Devote a thread to the periodic task. The thread can just loop calling sleep(1) and performing your periodic task.

但是我仍然认为您的方法应该有效.

But I still think your approach here should be working.

这篇关于POSIX计时器:计时器冻结的信号处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆