2017-08-08 70 views
0

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

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秒后发送数据的事件。

+1

你总是可以安排一个'SIGALRM'。但是,您的报警处理程序必须是信号安全的。如果你不知道这意味着什么,那对你来说不会是一种选择。除此之外,执行线程在指定的时间段之后执行某些操作的唯一方法是在指定的时间段内执行sleep(),poll()或select()在做出安排之后,将不会发生任何其他轮询/选择)。那些是你的选择。 –

+0

@Sam你能告诉我如何使用SIGALRM信号。谢谢 – Harry

+0

你可以让你的主线程成为接收数据的主线程,并将它引入一个由任务线程池处理的“任务队列”。使用条件变量,线程池可以休眠,直到最早的8秒钟过去,第一个任务已准备好处理。您的队列将始终按最早的开始时间排序。没关系,我看到你不能使用C++ 11。 –

回答

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"); 
}); 
+0

我使用的是RHEL 5,所以编译器不支持C++ 11标准。还有其他选择吗? – Harry

+0

我建议你找一个'pthread' C++包装器,它不需要C++ 11,或者,如果你不介意安装boost库的一部分,那就去'boost :: thread'。 –

0

你可以使用boost ::睡眠,或时:: sleep_for或时:: sleep_until, 但如果你不想呼吁睡觉,因为你是我最好的建议是使用std ::互斥体并锁定从Time.currenttime -StartTime ==接收信息线程8

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 

注:

这是一个从无到有的定制implementa灰。您可以将main重命名为ScheduleTimer,它将是一个通用API,它会生成一个线程并在其自己的上下文中调用已注册的回调。

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

方法-2

参考C: SIGALRM - alarm to display message every second的SIGALRM。可能在信号处理程序中,您可以将事件发布到您的线程将要监控的队列中

0

睡觉,无论是通过C++包装还是通过系统的nanosleep函数 - 不能说经常都不够 - 错了。除非精确性和可靠性完全不重要,否则不要睡觉。决不。
对于与时间有关的任何事情,请使用计时器

如果可移植性不是高优先级,并且由于该问题被标记为“Linux”,则timerfd将是最佳解决方案之一。

可以等待timerfd与select/poll/epoll等待接收的东西,和其他东西(信号,事件)在同一时间。这非常优雅,而且性能也很高。

被承认,因为你使用的是UDP,所以有一种诱惑就是不要等待第一个准备就绪,而只需要有recvfrom块。然而,等待准备就绪并不存在固有的错误。对于中等负载,额外的系统调用并不重要,但对于超高负载,您甚至可以考虑进一步进入非便携式的土地,并使用recvmmsg一次接收多个数据报,如报告的数据报数通过epoll(参见recvmmsg手册页上的代码示例,其结合了recvmmsgepoll_wait)。

使用eventfd,您可以在一个单一事件循环中将所有内容都放在一个单独的线程中,可靠高效。不需要任何欺骗,不需要特别聪明,不必担心并发问题。