【问题标题】:WaitableTimer with variable period具有可变周期的 WaitableTimer
【发布时间】:2014-10-26 10:34:35
【问题描述】:

我需要设置一个定期执行的可等待计时器。

问题如下,周期每 X(比如 5 个)周期变化一次,具体取决于系统在最后这 5 个周期内执行任务所花费的时间。

我尝试使用自动重置等待计时器,它在每次迭代后设置(5 次中有 4 次具有相同的间隔)。但是,时间与我设置的时间无关。相关代码如下所示。 (一切都始于对 HandleSensor 的调用)

    float AnalysisClient::GetNewInterval()
    {
        ...
            return newInterval;
    }

    VOID CALLBACK AnalysisClient::TimerFinished(LPVOID lpArg,
        DWORD dwTimerLowValue,
        DWORD dwTimerHighValue)
    {
        LARGE_INTEGER t;
        AnalysisClient* This = (AnalysisClient*)lpArg;
        This->readsensor();

        t.QuadPart = GetNewInterval() * 10000i64;
        SetWaitableTimer(_sensorTimer, &t, 0, TimerFinished, This, TRUE);
    }


    void AnalysisClient::WaitForsensor()
    {
        LARGE_INTEGER t;
        t.QuadPart = 0;
        SetWaitableTimer(_sensorTimer, &t, 0, TimerFinished, this, TRUE);

        SleepEx(
            INFINITE,           // Wait forever.
            TRUE);
    }



    void AnalysisClient::readsensor()
    {
        EnterCriticalSection(&_sensorCS);
        {
            while (_numsensorSampled >= _capacity) //no more sensors than the capacity size
            {
                UtilsLog("Queue full, not doing more sensor readings", UtilsDebug);
                SleepConditionVariableCS(&_sensorQueueFullCV, &_sensorCS, INFINITE);
            }

            UtilsLog("Read sensor", UtilsDebug);
            void* sensorreading = _fnSamplesensor();
            _numsensorSampled++;
            _localsensorQueue.push(sensorreading);
            _sensorHandler->Sendreading(sensorreading);
        }
        WakeConditionVariable(&_sensorQueueEmptyCV);
        LeaveCriticalSection(&_sensorCS);
    }

    void* AnalysisClient::Handlesensor()
    {
        //Spawn async thread if not already started

        if (!_asyncsensorHandlerStarted)
        {
            _asyncsensorHandlerStarted = true;
            CreateUtilsThread(Asyncreadsensor, this);
        }



        //Free memory from previous invocations
        ...

            void* returnVal = NULL;


        EnterCriticalSection(&_sensorCS);
        {
            while (_localsensorQueue.empty())
                SleepConditionVariableCS(&_sensorQueueEmptyCV, &_sensorCS, INFINITE);

            _lastreading = _localsensorQueue.front();
            _localsensorQueue.pop();
            returnVal = _lastreading;

            _numsensorProcessed++;
        }
        LeaveCriticalSection(&_sensorCS);

        return returnVal;
    }



    DWORD WINAPI AnalysisClient::Asyncreadsensor(void* Param)
    {
        //Create sensor Timer
        _sensorTimer = CreateWaitableTimer(NULL, FALSE, NULL);
        if (!_sensorTimer)
        {
            UtilsLog("Unable to create sensor waitable timer", UtilsError);
            return 1;
        }

        AnalysisClient* This = (AnalysisClient*)Param;
        This->WaitForsensor();
        return 0;
    }


bool CreateKahawaiThread(LPTHREAD_START_ROUTINE function, void* instance)
{
   DWORD ThreadID;
   HANDLE thread = CreateThread(NULL,0,function, instance, 0, &ThreadID);

   if(thread==NULL)
       return false;

   return true;
}

执行日志显示以下执行(右侧的数值是消息写入日志的时间(以毫秒为单位)。zi 调整了对 GetNewInterval 的调用以始终返回 1600000i64,因此我可以将其丢弃为问题。仍然与定时器调用之间的时间无关。可以看出容量设置为5。

        30621, Read sensor

        30623, Read sensor

        30624, Read sensor

        30625, Read sensor

        30626, Read sensor

        30627, Queue full, not doing more sensor readings

        30980, Read sensor

        30981, Queue full, not doing more sensor readings

        30997, Read sensor

        30998, Queue full, not doing more sensor readings

        31007, Read sensor

        31008, Queue full, not doing more sensor readings

        31019, Read sensor

        31020, Queue full, not doing more sensor readings

        31032, Read sensor

        31033, Queue full, not doing more sensor readings

        31040, Read sensor

        31041, Queue full, not doing more sensor readings

        31054, Read sensor

        31055, Queue full, not doing more sensor readings

        31066, Read sensor

        31068, Queue full, not doing more sensor readings

        31080, Read sensor

        31081, Queue full, not doing more sensor readings

        31087, Read sensor

        31088, Queue full, not doing more sensor readings

        31094, Read sensor

        31096, Queue full, not doing more sensor readings

        31111, Read sensor

        31112, Queue full, not doing more sensor readings

        31121, Read sensor

        31123, Queue full, not doing more sensor readings

        31180, Read sensor

        31181, Queue full, not doing more sensor readings

        31194, Read sensor

        31197, Queue full, not doing more sensor readings

        31294, Read sensor

        31295, Queue full, not doing more sensor readings

        31307, Read sensor

        31308, Queue full, not doing more sensor readings

        31316, Read sensor

        31318, Queue full, not doing more sensor readings

        31332, Read sensor

        31333, Queue full, not doing more sensor readings

        31336, Read sensor

        31337, Queue full, not doing more sensor readings

        31343, Read sensor

        31344, Queue full, not doing more sensor readings

        31359, Read sensor

        31360, Queue full, not doing more sensor readings

        31369, Read sensor

        31371, Queue full, not doing more sensor readings

        31384, Read sensor

        31385, Queue full, not doing more sensor readings

        31391, Read sensor

        31392, Queue full, not doing more sensor readings

        31398, Read sensor

        31399, Queue full, not doing more sensor readings 

什么是错误?有没有更好的方法来实现这一点?

谢谢

【问题讨论】:

  • 不应该WakeConditionVariable(&_sensorQueueEmptyCV); LeaveCriticalSection(&_sensorCS); 保留订单吗?
  • Windows 不以可靠的计时而闻名...我想我在某处读到过,Windows 只允许计时器在预期到期之前不会到期。当您的应用程序处理计时器时,情况就完全不同了。可能有帮助的一件事是提高应用程序的优先级(请参阅SetPriorityClass
  • 我已经用 while 循环和 Sleep 调用解决了这个问题。它更简单,效果更好。说实话,Surt 是对的,我把顺序颠倒了,这可能是问题的一部分。最后,我同意 Lukas 的观点,即它不可靠。我确实只想要那个保证(之前没有过期),但它并没有以某种方式做到这一点

标签: c++ windows multithreading winapi timer


【解决方案1】:

你有

        while (_numsensorSampled >= _capacity) //no more sensors than the capacity size

        _localsensorQueue.push(sensorreading);
        _numsensorSampled++;

        _localsensorQueue.pop();
        returnVal = _lastreading;

        _numsensorProcessed++;

但是没有

        --_numsensorSampled;

所以

        while (_numsensorSampled >= _capacity) //no more sensors than the capacity size

当你达到这个数字时总是如此。把它改成

        while (_numsensorSampled - numsensorProcessed >= _capacity) //no more sensors than the capacity size

也应该让它工作。还有

    WakeConditionVariable(&_sensorQueueEmptyCV);
    LeaveCriticalSection(&_sensorCS);

看起来不对,应该是

    LeaveCriticalSection(&_sensorCS);
    WakeConditionVariable(&_sensorQueueEmptyCV);

否则被唤醒的进程可能会立即再次进入睡眠状态,因为关键部分仍处于活动状态。

【讨论】:

  • 其实是对的,我把它们倒过来了。最后,我使用了睡眠呼叫,令人惊讶的是,它效果更好,而且简单得多。 --numsensorsampled 顺便说一句,在代码中的其他地方。
猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 2021-05-13
相关资源
最近更新 更多