C ++中的事件调度

时间:2017-08-08 11:32:42

标签: c++ c linux sockets

我正在构建一个应用程序,我在其中接收套接字数据。我需要在几秒钟后回复这些收到的数据(比如说8秒后)。所以我想知道有没有办法安排一个事件,它会在8秒后自动发送套接字数据。我不喜欢在接收线程或任何其他线程中不必要地睡8秒。这是我到目前为止所写的用于接收pthread的套接字数据。

long DataSock_fd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

    StSocketAddress.sin_family=AF_INET; //address family
    StSocketAddress.sin_addr.s_addr=inet_addr("10.10.10.10");   //load ip address
    StSocketAddress.sin_port=htons(1234);   //load port number
    //bind the above socket to the above mentioned address, if result is less than 0(error in binding)
    if(bind(DataSock_fd,(struct sockaddr *)&StSocketAddress,sizeof(StSocketAddress))<0)
    {
        close(DataSock_fd); //close the socket
        perror("error while binding\n");
        exit(EXIT_FAILURE); //exit the program
    }

char Buff[1024];
long lSize = recvfrom(DataSock_fd,(char *)Buff,sizeof(Buff),0,NULL,NULL);

但我坚持安排一个在8秒后发送数据的事件。

4 个答案:

答案 0 :(得分:1)

看看这个SO answer

您可以像这样使用<async>来解决您的问题:

auto f = std::async(std::launch::async, [] {
    std::this_thread::sleep_for(std::chrono::seconds(5));
    printf("(5 seconds later) Hello");
});

答案 1 :(得分:0)

你可以使用boost :: sleep,或chrono :: sleep_for或chrono :: sleep_until, 但是如果你不想打电话给睡眠,我最好的建议是使用std :: mutex并锁定从Time.currenttime -startTime == 8接收信息的线程。

答案 2 :(得分:0)

<强>方法-1

由于您没有启用C++11编译器,并假设您没有使用Qt / boost等框架。请检查以下代码是否回答了您的问题。它是使用pthreads

的简单异步计时器实现

示例代码:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>

#define TIME_TO_WAIT_FOR_SEND_SECS (8)
#define FAIL_STATUS_CODE (-1)
#define SUCCESS_STATUS_CODE (0)

typedef void (*TimerThreadCbk)(void *);
typedef struct tTimerThreadInitParams
{
   int m_DurationSecs; /* Duration of the timer */
   TimerThreadCbk m_Callback; /* Timer callback */
   void * m_pAppData; /* App data */

}tTimerThreadInitParams;

void PrintCurrTime()
{
    time_t timer;
    char buffer[26];
    struct tm* tm_info;

    time(&timer);
    tm_info = localtime(&timer);

    strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
    puts(buffer);
}

void* TimerThreadEntry(void *a_pTimerThreadInitParams)
{
  tTimerThreadInitParams *pTimerThreadInitParams = (tTimerThreadInitParams *)a_pTimerThreadInitParams;
  if(NULL != pTimerThreadInitParams)
  {
    /*Do validattion of init params */
    sleep(pTimerThreadInitParams->m_DurationSecs);
    pTimerThreadInitParams->m_Callback(pTimerThreadInitParams->m_pAppData);
  }
  else
  {
     printf("pTimerThreadInitParams is (nil)\n");
  }   
}

TimerCallbackForSend(void *a_pAppData)
{
   (void)a_pAppData;
   /* Perform action on timer expiry using a_pAppData */
   printf("TimerCallbackForSend trigggered at: ");
   PrintCurrTime();
}

int main()
{
   /* Timer thread initialization parameters */
   pthread_t TimerThread;
   tTimerThreadInitParams TimerInitParams = {};
   TimerInitParams.m_DurationSecs = TIME_TO_WAIT_FOR_SEND_SECS;
   TimerInitParams.m_Callback = (TimerThreadCbk) TimerCallbackForSend;

   /* Print current time */ 
   printf("Starting timer at:");
   PrintCurrTime();

   /* Create timer thread*/
   if(pthread_create(&TimerThread, NULL, TimerThreadEntry, &TimerInitParams)) 
   {
     fprintf(stderr, "Error creating thread\n");
     return FAIL_STATUS_CODE;
   }
   else
   {
     printf("TimerThread created\n");
   }

   /* wait for the second thread to finish */
   if(pthread_join(TimerThread, NULL))
   {
     fprintf(stderr, "Error joining thread\n");
     return FAIL_STATUS_CODE;
   }
   else
   {
      printf("TimerThread finished\n");
   }
   return SUCCESS_STATUS_CODE;
}

示例输出:

Starting timer at:2017-08-08 20:55:33
TimerThread created
TimerCallbackForSend trigggered at: 2017-08-08 20:55:41
TimerThread finished

备注:

这是一个临时自定义实现。您可以将main重命名为ScheduleTimer,这将是一个通用API,它会生成一个线程并在其自己的上下文中调用已注册的回调。

刚才看到你不想在任何一个线程中睡觉。

<强>方法-2

请参阅C: SIGALRM - alarm to display message every second以获取SIGALRM。可以在信号处理程序中,您可以将事件发布到您的线程将监视的队列

答案 3 :(得分:0)

无论是通过C ++包装还是通过系统的nanosleep函数进行休眠 - 它都不能说得足够 - 是错误的。除非精确性和可靠性根本不重要,否则不要睡觉。从来没有。
对于与计时相关的任何事情,请使用计时器

如果可移植性不是高优先级,并且由于问题被标记为&#34; Linux&#34;,timerfd将是最好的解决方案之一。

在等待接收某些内容时,可以使用select / poll / epoll等待timerfd,同时等待其他内容(信号,事件)。这非常优雅,也非常高效。

承认,既然您正在使用UDP,那么首先不要等待准备就绪,而是要recvfrom阻止。然而,等待准备就没有什么本质上的错误。对于中等负载,额外的系统调用并不重要,但对于超高负载,您甚至可以考虑进一步进入非便携式土地并使用recvmmsg一次性接收多个数据报,如图所示按epoll报告的数据报数量(请参阅recvmmsg手册页上的代码示例,其中recvmmsgepoll_wait合并。)

使用eventfd,您可以在一个单个线程中将所有内容放在一个单一的事件循环中,可靠且高效。不需要任何技巧,不需要太聪明,不用担心并发问题。