在C ++ 11中实现看门狗定时器

时间:2016-03-06 08:48:31

标签: c++ c++11 timer watchdog

我试图在C ++ 11中实现一个小型看门狗定时器类,它应该在过期时调用一些代码。

Watchdog.h:

Dim questionNumber As Integer = Random.Next(1, (File.ReadLines("<yourQuestions.txt").Count() / 6) + 1)
Dim blockLines = File.ReadLines("<yourQuestions.txt").Skip((questionNumber - 1) * 6).Take(6)
Dim currentQuestion As New Question(blockLines(0), blockLines(1), blockLines(2), blockLines(3), blockLines(4), blockLines(blockLines(5)))

Watchdog.cpp:

#pragma once

#include <thread>
#include <atomic>

class Watchdog
{
public:
    Watchdog();
    Watchdog(unsigned int milliseconds, std::function<void()> callback);
    ~Watchdog();

    void Start(unsigned int milliseconds, std::function<void()> callback);
    void Stop();
    void Pet();

private:
    unsigned int _interval;
    std::atomic<unsigned int> _timer;
    std::atomic<bool> _running;
    std::thread _thread;
    std::function<void()> _callback;

    void Loop();
};

然而,这个线程循环对我来说似乎有点脏,而且#include "Watchdog.h" Watchdog::Watchdog() : _interval(0), _timer(0), _running(false) { } Watchdog::Watchdog(unsigned int milliseconds, std::function<void()> callback) { Start(milliseconds, callback); } Watchdog::~Watchdog() { } void Watchdog::Start(unsigned int milliseconds, std::function<void()> callback) { _interval = milliseconds; _timer = 0; _callback = callback; _running = true; _thread = std::thread(&Watchdog::Loop, this); } void Watchdog::Stop() { _running = false; _thread.join(); } void Watchdog::Pet() { _timer = 0; } void Watchdog::Loop() { while (_running) { _timer++; if (_timer >= _interval) { _running = false; _callback(); } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } 不准确(它睡觉时至少指定的数量,这意味着它可能超过1毫秒) ,有没有更好的方法来实现这个功能?

2 个答案:

答案 0 :(得分:0)

似乎很有趣,我可以想出这段代码。 它没有编译,你必须在它上面做很多工作,但它显示了一个关于如何做的想法。

std::mutex cmutex;  // needed for the condition_variable
std::condition_variable stop_condition;
std::chrono::time_point   last_pet_time;

void Watchdog::Start(unsigned int milliseconds, std::function<void()> callback)
{
    // somewhere in this method:
    last_pet_time = now();
    timeout = milliseconds;
}


void Watchdog::Stop()
{
    if (_running) {
        std::unique_lock<std::mutex> lock(cmutex);

        _running = false;
        stop_condition.notify_all(); // tell Loop() to stop

        _thread.join();
    }
}

void Watchdog::Pet()
{
    std::unique_lock<std::mutex> lock(cmutex);

    last_pet_time = now();
}


void Watchdog::Loop()
{
    std::unique_lock<std::mutex> lock(cmutex);

    while (_running                                 // was Stop() called?
           and (now() - last_pet_time) < timeout)   // was Pet() ( or Start() ) called recently?
    {
        // here the threads waits until:
        //  1. the condition_variable is notified in ::Stop()
        //  2. or the timeout expires
        //  3. or until spurious wakeup
        stop_condition.wait_for(lock, timeout);

    }
    if (_running) {
        _running = false;
        callback();
    }
}

检查:http://en.cppreference.com/w/cpp/thread/condition_variable/wait_until

答案 1 :(得分:0)

这应该有效。真的有两节课。一个用于处理通知(AutoResetEvent)和Watchdog类本身。

AutoResetEvent.h

#pragma once
#include <mutex>
class AutoResetEvent
{
private:
    bool m_ready = true;
    std::condition_variable m_condition;
    std::mutex m_mutex;
public:
    AutoResetEvent();
    ~AutoResetEvent();
    void WaitOne();
    void WaitFor(unsigned __int32 milli_secs);
    void Notify();
};

AutoResetEvent.cpp

AutoResetEvent::AutoResetEvent()
{
}


AutoResetEvent::~AutoResetEvent()
{
    Notify();
}

void AutoResetEvent::Notify()
{
    if (!m_ready)
    {
        std::unique_lock<std::mutex> locker(m_mutex);
        m_ready = true;
        m_condition.notify_all();
    }
}

void AutoResetEvent::WaitOne()
{
    std::unique_lock<std::mutex> locker(m_mutex);
    m_ready = false;
    m_condition.wait(locker, [&ready = m_ready]() {return ready; });
}

void AutoResetEvent::WaitFor(unsigned __int32 milli_secs)
{
    std::unique_lock<std::mutex> locker(m_mutex);
    m_ready = false;
    m_condition.wait_for(locker, std::chrono::milliseconds(milli_secs), [&ready = m_ready]() {return ready; });
}

Watchdog.h

#pragma once
#include "AutoResetEvent.h"
#include <functional>
class Watchdog
{
private:
    const unsigned __int32 WATCHDOG_BEEP_MS = 5*60*1000;

    bool m_active_status = false;
    bool m_new_pet = false;
    bool m_cancelled = false;

    AutoResetEvent m_reset_event;
    std::function<void(void)> m_call_back;

    void Loop();
public:
    Watchdog(std::function<void(void)> call_back);
    ~Watchdog();
    bool Start();
    void Pet();
    void Stop();

    bool IsActive() const;
};

Watchdog.cpp

    #include "stdafx.h"
    #include "Watchdog.h"

    void Watchdog::Loop()
    {
        m_active_status = true;
        m_cancelled = false;
        while (true)
        {
            m_new_pet = false;
            m_reset_event.WaitFor(WATCHDOG_BEEP_MS);
            if (!m_new_pet && !m_cancelled)
            {
                m_call_back();
                break;
            }
            if (m_cancelled)
            {
                break;
            }
        }
        m_active_status = false;
    }

    Watchdog::Watchdog(std::function<void(void)> call_back): m_call_back(call_back)
    {
    }
    Watchdog::~Watchdog()
    {
        Stop();
    }
    bool Watchdog::Start()
    {
        if (IsActive()) return false;
        std::thread loop_thread(&Watchdog::Loop, this);
        loop_thread.detach();
        return true;
    }


    void Watchdog::Pet()
    {
        if (!IsActive()) return;
        m_new_pet = true;
        m_reset_event.Notify();
    }

    void Watchdog::Stop()
    {
        if (!IsActive()) return;
        m_cancelled = true;
        m_reset_event.Notify();
    }

    bool Watchdog::IsActive() const
    {
        return m_active_status;
    }