如何基于固定的循环频率正确地协调线程? [英] How to coordinate threads properly based on a fixed cycle frequency?

查看:84
本文介绍了如何基于固定的循环频率正确地协调线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个网关来传递来自can总线和lcm的消息,反之亦然.如果以特定的频率发送以lcm为单位的消息,则应以完全相同的频率发送其在can总线上的副本.

I want to create a gateway to pass messages from a can bus and lcm and vice-versa. If a message in lcm is sent at a specific frequency, its copy on the can bus should be sent at the exact same frequency.

您将如何解决?

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

In my mind I thought about two threads, one for each direction converting the message from one system to another in a loop. The two threads are coordinated by a timer which is set to a frequency which is much lower than the maximum message passing frequency possible. The timer sents a signal to the threads after each cycle. The threads wait for that event at the end of each loop, i.e. they sleep and free resources until the event occures. I implemented this idea already but the resulting frequencies are not constant. Am I doing something conceptually wrong?

解决方案应在Windows上运行,因此可以利用本地Windows api或boost线程.网关应该具有实时功能.

A solution should run on windows, thus utilize either native windows api or boost threads for example. The gateway should be real-time capable.

推荐答案

对于Windows,

For windows, timeSetEvent can be used to set an event at a regular interval, although MSDN lists it as an obsolete function. The replacement for timeSetEvent uses a callback function, so you'd have to set an event in the callback function.

您可以使用某些游戏的线程以固定频率运行,并在当前周期中有足够的延迟时间时轮询高频计数器和睡眠"状态.为了防止漂移,该延迟基于高频计数器的原始读数.与Windows XP兼容的示例代码,其中Sleep(1)最多需要2毫秒. dwLateStep是一种诊断工具,如果代码超过周期时间,则递增.

Some games have threads that run at fixed frequencies, and poll a high frequency counter and Sleep when there's enough delay time remaining in the current cycle. To prevent drift, the delay is based off an original reading of the high frequency counter. Example code that is Windows XP compatible, where a Sleep(1) can take up to 2 milliseconds. dwLateStep is a diagnostic aid and incremented if the code exceeds a cycle period.

/* 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 */

这篇关于如何基于固定的循环频率正确地协调线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆