【问题标题】:How to coordinate threads properly based on a fixed cycle frequency?如何根据固定的循环频率正确协调线程?
【发布时间】:2015-09-28 03:59:59
【问题描述】:

我想创建一个网关来传递来自 can bus 和 lcm 的消息,反之亦然。如果 lcm 中的消息以特定频率发送,则它在 can bus 上的副本应该以完全相同的频率发送。

你会怎么解决这个问题?

在我的脑海中,我想到了两个线程,一个用于将消息从一个系统循环到另一个系统的每个方向。这两个线程由一个计时器协调,该计时器设置为比可能的最大消息传递频率低得多的频率。计时器在每个周期后向线程发送一个信号。线程在每个循环结束时等待该事件,即它们休眠并释放资源,直到事件发生。 我已经实现了这个想法,但产生的频率不是恒定的。我在概念上做错了吗?

解决方案应该在 Windows 上运行,例如使用原生 Windows api 或 boost 线程。网关应该是实时的。

【问题讨论】:

  • 为什么不是两个线程从一个总线读取并立即写入另一个总线?

标签: c++ windows multithreading controls real-time


【解决方案1】:

对于 Windows,timeSetEvent 可用于定期设置事件,尽管 MSDN 将其列为过时函数。 timeSetEvent 的替换使用了回调函数,所以你必须在回调函数中设置一个事件。

您可以使用 timeBeginPeriod 将滴答频率从默认的 64hz == 15.625 毫秒降低到 1 毫秒

一些游戏的线程以固定频率运行,并在当前周期剩余足够的延迟时间时轮询高频计数器和睡眠。为了防止漂移,延迟基于高频计数器的原始读数。与 Windows XP 兼容的示例代码,其中 Sleep(1) 最多可能需要 2 毫秒。 dwLateStep 是一种诊断辅助工具,如果代码超过一个循环周期,它就会增加。

/* code for a thread to run at fixed frequency */
typedef unsigned long long UI64;        /* unsigned 64 bit int */
#define FREQ    400                     /* frequency */
DWORD    dwLateStep;                    /* late step count */
LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
LARGE_INTEGER liPerfTemp;               /* used for query */
UI64 uFreq = FREQ;                      /* process frequency */
UI64 uOrig;                             /* original tick */
UI64 uWait;                             /* tick rate / freq */
UI64 uRem = 0;                          /* tick rate % freq */
UI64 uPrev;                             /* previous tick based on original tick */
UI64 uDelta;                            /* current tick - previous */
UI64 u2ms;                              /* 2ms of ticks */
UI64 i;

    /* ... */ /* wait for some event to start thread */
    QueryPerformanceFrequency(&liPerfFreq);
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);

    timeBeginPeriod(1);                 /* set period to 1ms */
    Sleep(128);                         /* wait for it to stabilize */

    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
    uOrig = uPrev = liPerfTemp.QuadPart;

    for(i = 0; i < (uFreq*30); i++){
        /* update uWait and uRem based on uRem */
        uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
        uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
        /* wait for uWait ticks */
        while(1){
            QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
            uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
            if(uDelta >= uWait)
                break;
            if((uWait - uDelta) > u2ms)
                Sleep(1);
        }
        if(uDelta >= (uWait*2))
            dwLateStep += 1;
        uPrev += uWait;
        /* fixed frequency code goes here */
        /*  along with some type of break when done */
    }

    timeEndPeriod(1);                   /* restore period */

【讨论】:

  • 感谢您的快速回复,我将在下周尝试,如果它可以解决我的问题给您反馈
猜你喜欢
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 2015-03-26
  • 1970-01-01
  • 2021-07-03
相关资源
最近更新 更多