C中的多个计时器

时间:2013-09-17 10:52:20

标签: c process timer signals alarm

我有一个需要执行以下操作的应用程序:

  • 如果发生事件(与服务器断开连接),则启动长计时器(例如5分钟)。然后,应用程序尝试重新连接到服务器。
  • 如果重新连接失败,将启动一个短计时器(20秒),该计时器应尝试重新连接。
  • 如果成功,长计时器保持继续。
  • 当长计时器到期时,如果没有连接,应该退出应用程序,否则它应该继续正常。

我受限于我不能使用线程,只能使用进程。我也无法等待reconnect()返回的结果。

到目前为止,我有这样的设计:

int main(int argc, char **argv)
{
    /* do main loop work, if disconnected, call reconnect() & continue doing work */
}

void reconnect()
{
    pid = fork();

    if (pid >= 0) {
        /*Successful fork*/
        if (pid == 0) {

            rv = attempt_reconnect;               
            if (rv == 0) {
                /*Notify sig_child Success*/
                exit(0);
            } else {
                /*Notify sig_child Fail*/
                exit(1);
            }
        }
    } 
}

void sig_child(int signum)
{
    if(fork returned success) {
        set flag to continue network stuff
    }
    else {
        alarm(20);
    }
}

void sig_alarm(int signo)
{
    /*Received alarm, trying to reconnect...*/
    reconnect();
}

非常感谢任何帮助!

修改

我想我的解决方案是here。它允许我创建具有单独ID的计时器,然后识别哪个已经发信号通知程序

4 个答案:

答案 0 :(得分:2)

使用以下代码I found here,我已经实现了(我认为)我想要做的事情。

它允许分别使用函数“makeTtimer”和“timerHandler”创建和处理多个timer_t对象:

timer_t reconnect_timer_id;
timer_t timeout_timer_id;

int main(int argc, char **argv)
{
    /* do main loop work */
    if(disconnected()) {
        /*IF TIMEOUT SET, SKIP, IF OK, RESET*/
        if(timeout_set != 1) {
            "Schedule Alarm"
            makeTimer("Timeout Timer", &timeout_timer_id, 600,0);
            timeout_set = 1;
        } else {
              "Timeout alarm already set..";
        }
        reconnect();
    }
}

void reconnect()
{
    pid = fork();

    if (pid >= 0) {
        /*Successful fork*/
        if (pid == 0) {

            rv = attempt_reconnect;               
            if (rv == 0) {
                /*Notify sig_child Success*/
                exit(0);
            } else {
                /*Notify sig_child Fail*/
                exit(1);
            }
        }
    } 
}

void sig_child(int signum)
{
    if(fork returned success) {
        set flag to continue network stuff
    }
    else {
        "Reconnect fail, retrying in 20 seconds...";
        makeTimer("Reconnect Timer", &reconnect_timer_id, 20,0);
    }
}

static void
timerHandler( int sig, siginfo_t *si, void *uc )
{
    timer_t *tidp;
    tidp = si->si_value.sival_ptr;
    if ( *tidp == timeout_timer_id ) {

        if(state != STATE_CONNECTED) {
            "Timeout alarm received, not connected to server, exiting..."
            exit(0);
        } else {
            "Timeout alarm received, connected to server, continuing..."
            timeout_set = 0;
        }

    } else if ( *tidp == reconnect_timer_id ) {
        "Reconnect alarm received, retrying...";
        reconnect();
    }
}

static int
makeTimer( char *name, timer_t *timerID, int expireSeconds, int intervalSeconds )
{
    struct sigevent         te;
    struct itimerspec       its;
    struct sigaction        sa;
    int sigNo = SIGRTMIN;

    /* Set up signal handler. */
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timerHandler;
    sigemptyset(&sa.sa_mask);

    if (sigaction(sigNo, &sa, NULL) == -1) {
          "Failed to setup signal handling for" *name;

        return(-1);
    }

    /* Set and enable alarm */
    te.sigev_notify = SIGEV_SIGNAL;
    te.sigev_signo = sigNo;
    te.sigev_value.sival_ptr = timerID;
    timer_create(CLOCK_REALTIME, &te, timerID);
    its.it_interval.tv_sec = intervalSeconds;
    its.it_interval.tv_nsec =0;

    its.it_value.tv_sec = expireSeconds;
    its.it_value.tv_nsec = 0;
    timer_settime(*timerID, 0, &its, NULL);
    return(0);
}

答案 1 :(得分:1)

一个想法可能不是使用alarm( ),而是创建定时器作为kill sleep() void timer( int nsec, int signum ) { pid_t pid = getpid(); if( fork() > 0 ) { sleep( nsec ); kill( pid, signum ); exit( 0 ); } } 之后具有两个不同信号的主要过程的子过程:

void sig_timer( int signum )
{
    if( signum == SIGUSR1 ) {
        // reconnect
    } else if( signumm == SIGUSR2 ) {
        if( !reconnected )
            exit( 11 );
    } 
}

通过使用两个不同的信号(例如,用于短定时器的SIGUSR1和用于长定时器的SIGUSR2),您可以拥有这样的信号处理器:

{{1}}

答案 2 :(得分:1)

您只能通过在主循环中轮询它们来使用警报和标志来执行此操作。在主循环中选择断开事件后,您可以设置20秒的警报并使用标志处理处理程序或主循环中的重新连接。继续设置20秒的警报,直到您重新连接或5五分钟到期。如果20秒警报发生15次,您可以在警报处理程序中再次检查此项。 现在如果5分钟到期,则可以重置警报(0)并通知主循环关闭。 这样的事情。

int disconnect_event = 0;
int reconnect_try = 1;
int five_minutes  = 0;
int shutdown = 0;
void alarm_handler(int signum)
{
  if(five_minutes == 15)
  {
    alarm(0);
    shutdown = 1;
  }
  else
  {
    reconnect_try = 1;
    alarm(20);
    five_minutes++
  }

} 

int main(int argc, char*argv[])
{
  signal(SIGALRM, alarm_handler);
  while(1)
  {
    if(disconnect_event && reconnect_try)
    {
      if(reconnect() == 0)
      {
        alarm(20);
        reconnect_try = 0;
      }
      else
      {
         disconnect_event = 0;
         reconnect_try = 1;
      }
    }
    if(shutdown)
    {
      disconnect_event = 0;
      reconnect_try = 0;
      alarm(0)
    }

  }

}

答案 3 :(得分:0)

从问题中不清楚应用程序是否需要在connect()正在进行时继续运行(1),以及(2)当它处于“短暂等待”时。

如果需要在这些时段中的任何一个中运行,那么当您需要使用长计时器时,将长计时器到期的绝对时间放入某个变量,如下:

time_t run_until = time(NULL) + 60;

并且在每次不成功的connect()之后检查当前时间是否大于run_until:

if (connect_rc) {if (time(NULL) > run_until) shutdown(); else reconnect();}

您将获得上述逻辑,而无需任何进程或线程。

如果您需要在connect()正在进行时继续运行,和/或在重新连接之前处于短暂暂停状态,则可以使用非阻塞套接字。怎么做是一个冗长的讲座问题;本质上,你围绕select()或poll()安排你的主循环。这些函数允许您等待一组事件中的一个发生,事件是:完成后台connect(),或者到达数据准备好recv()/ read(),或者重要的是,计时器到期。这种方法也不涉及线程或进程。