2017-08-08 36 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,您可以在一個單一事件循環中將所有內容都放在一個單獨的線程中,可靠高效。不需要任何欺騙,不需要特別聰明,不必擔心併發問題。