2016-03-10 96 views
2

目標是在具有固定增量時間的後臺線程上調用函數。C++ - 具有固定增量時間的循環POSIX線程

函數應該被調用60次/秒,因此在時間戳0,0.0166等時間戳應儘可能精確地命中。

簡單但可能不是最好的解決方案是運行一段時間(true)-loop並讓線程休眠直到下次調用該函數。這裏有一半C++ /半僞代碼它是如何做到的。

float fixedDeltaTime = 1.0/60.0; 
void loopFunction() 
{ 
     while(true) 
     { 
     auto currentTime = getTime(); 
     // do work 
     auto timePassed = getTime() - currentTime; 
     int times = (timePassed/fixedDeltaTime); 
     sleep( (fixedDeltaTime * times) - timePassed) 
     } 
} 

int main() 
{ 
    std::thread loopFunction(call_from_thread); 
    return 0; 
} 

昨天,我問了一個同樣的問題,要求使用C++ 11 std :: thread的解決方案。評論中的一些人告訴我,使用POSIX線程會更好。雖然pthread對我來說似乎更加複雜,所以我希望這裏的某個人能告訴我如何用pthread來解決這個問題。

+2

你有什麼理由爲什麼你現在的解決方案不夠好? –

+0

嗯,是的。 std :: sleep_for不是很準確,所以我必須在非常小的時間間隔內執行,並檢查是否已調用loopFunction()的時間。在其他線程中,人們也表示計時時間測量非常昂貴。 – keyboard

+0

@keyboard - 由於我犯有提及定時器可能代價高昂的問題,因此將使用的實際增量時間是多少?如果它真的是0.0166,不要介意我對定時器性能的評論(除非你啓動100個並行線程)。再一次,如果你真的想要性能,在每個平臺上使用本機等待計時器,但我認爲這樣的超時時間太長了。 –

回答

1

Posix線程肯定授予之間前臺和後臺任務更快的通信速度,但如果你想精密我會建議使用clock_nanosleep跟蹤的時間在一個實時內核之上。

您可以使用以下基本功能來塑造你的任務生命週期:

#ifndef __TIMERS_H__ 
#define __TIMERS_H__ 

#include <stdint.h> /* uint64_t       */ 
#include <time.h> /* clockid_t of clock_nanosleep()  */ 

/*--------------------------------------------------------------------------------------*/ 

/* Common facility functions needed for 
* high precision timers usage 
*/ 

/*--------------------------------------------------------------------------------------*/ 

#define SEC_VAL 1000000000ULL 

enum return_values { 
    RETURN_FAILURE = 0, 
    RETURN_SUCCESS = 1, 
    RETURN_EMPTY = 2 
}; 

typedef void* timespec_ptr; 

typedef struct timespec timespec_t; 

/* Adds time_us microseconds to timer ts 
*/ 
void timespec_add_ns(timespec_ptr ts, 
     uint64_t time_ns); 
/* Makes the thread wait for the next activation of the timer ts 
*/ 
void wait_next_activation(timespec_ptr ts); /*** @ Tasks ***/ 
/* Starts the periodic timer 
*/ 
int start_periodic_timer(timespec_ptr ts, 
     uint64_t init_offs_ns); 

/* Computes the difference among two clocks 
*/ 
long calcdiff(struct timespec t1, 
     struct timespec t2); 

/*--------------------------------------------------------------------------------------*/ 

extern int clock_nanosleep(clockid_t clock_id, int flags, 
          const struct timespec* request, 
          struct timespec* remain); 

/*--------------------------------------------------------------------------------------*/ 

#endif 

這裏有實現文件:

#include "timers.h" 
#include <stdio.h> /* fprintf */ 

/*--------------------------------------------------------------------------------------*/ 

/* Adds time_us microseconds to timer ts 
*/ 
void timespec_add_ns(timespec_ptr ts, 
     uint64_t time_ns) 
{ 
    if (ts) 
    { 
     timespec_t* ts_ = (timespec_t*) ts; 

     time_ns += ts_->tv_nsec; 
     ts_->tv_sec += time_ns/SEC_VAL; 
     ts_->tv_nsec = time_ns%SEC_VAL; 
    } else { 
     fprintf(stderr, "Warning (%s): input argument is NULL, \ 
         request ignored.\n", __FUNCTION__); 
    } 
} 

/* Makes the thread wait for the next activation of the timer ts 
*/ 
void wait_next_activation(timespec_ptr ts) 
{ 
    if (ts) 
    { 
     timespec_t* ts_ = (timespec_t*) ts; 

     clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts_, NULL); 
    } else { 
     fprintf(stderr, "Warning (%s): input parameter is NULL, \ 
         request ignored.\n", __FUNCTION__); 
    } 
} 

/* Starts the periodic timer 
*/ 
int start_periodic_timer(timespec_ptr ts, 
     uint64_t init_offs_ns) /*** @ Tasks ***/ 
{ 
    if (ts) 
    { 
     timespec_t* ts_ = (timespec_t*) ts; 

     clock_gettime(CLOCK_MONOTONIC, ts_); 
     timespec_add_ns(ts, init_offs_ns); 
     return RETURN_SUCCESS; 
    } else { 
     fprintf(stderr, "Warning (%s): input parameter is NULL, \ 
         request ignored.\n", __FUNCTION__); 
     return RETURN_FAILURE; 
    } 
} 

/* Computes the difference among two clocks 
*/ 
long calcdiff(struct timespec t1, 
     struct timespec t2) /*** @ Tasks ***/ 
{ 
    long diff; 

    diff = SEC_VAL * ((int) t1.tv_sec - (int) t2.tv_sec); 
    diff += ((int) t1.tv_nsec - (int) t2.tv_nsec); 
    return diff; 
} 

/*--------------------------------------------------------------------------------------*/ 

後臺任務應主要做到以下幾點:

void run (void *args) { 
    start_periodict_timer(&timer_, offset); 
    while (true) { 
     wait_next_activation(&timer_); 
     timespec_add_ns(&timer_, period); 

     /* do your periodic task */ 

    } 
} 

其中偏移我是您開始執行任務時等待的初始時間,而期間是您在一次調用任務和另一次調用之間等待的時間。

+1

謝謝,但似乎我不能使用這個。我得到clockid_t(和更多)未聲明/找到。顯然這些東西不是在iOS和OSX上:http://stackoverflow.com/questions/13472761/unknown-type-name-clockid-t – keyboard

+0

@keyboard感謝突出顯示此限制。您是否嘗試過在iOS上使用nanosleep()/ usleep(),如果可用()? –