[英]C++ - Loop with fixed delta time on a background POSIX Thread
目标是在具有固定增量时间的后台线程上调用函数。
该函数应该被调用 60 次/秒,因此在时间戳 0、0.0166 等处。应该尽可能精确地命中时间戳。
简单但可能不是最好的解决方案是运行 while(true) 循环并让线程休眠,直到下次调用该函数时为止。 这是一半 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 线程会更好。 虽然 pthreads 对我来说似乎更复杂,所以我希望这里有人可以告诉我如何用 pthreads 解决这个问题。
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 */
}
}
其中offset是自您开始任务以来等待的初始时间,而period是您在一次任务调用和另一次调用之间等待的时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.