Boost Signals2 및 스레드를 사용하여 C ++에서 소프트웨어 Watchdog 타이머 스레드를 만들 수 있습니까?

StackOverflow https://stackoverflow.com/questions/1015494

문제

나는 현재 단일 스레드 응용 프로그램에서 다른 사람의 라이브러리에서 foot foo를 실행하고 있습니다. 대부분의 경우, 나는 Foo에게 전화를 걸고 정말 빠릅니다. 때로는 Foo에게 전화를 걸고 영원히 걸립니다. 나는 환자가 아니에요

제어 된 방식으로 FOO를 호출하는 가장 좋은 방법은 (내 현재 환경은 POSIX/C ++) 일정 수의 몇 초 후에 실행을 중지 할 수 있습니다. 여기서 옳은 일은 Foo를 호출 할 두 번째 스레드를 만드는 것인데, 메인 스레드에서는 타이머 함수를 만듭니다. 타이머 기능은 시간이 부족한 경우 두 번째 스레드를 신호합니다.

더 많은 적절한 모델 (및 솔루션)이 있습니까? 그렇지 않다면 Boost의 Signals2 라이브러리와 스레드가 트릭을 수행합니까?

도움이 되었습니까?

해결책

타임 아웃으로 두 번째 스레드에서 foo를 호출 할 수 있습니다. 예를 들어:

#include <boost/date_time.hpp> 
#include <boost/thread/thread.hpp>

boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(500);
boost::thread thrd(&Foo);

if (thrd.timed_join(timeout))
{
  //finished
}
else
{
  //Not finished;
}

다른 팁

다음 클래스를 사용할 수 있습니다.

class timer
{
    typedef boost::signals2::signal<void ()> timeout_slot;
public:
    typedef timeout_slot::slot_type timeout_slot_t;

public:
    timer() : _interval(0), _is_active(false) {};
    timer(int interval) : _interval(interval), _is_active(false) {};
    virtual ~timer() { stop(); };

    inline boost::signals2::connection connect(const timeout_slot_t& subscriber) { return _signalTimeout.connect(subscriber); };

    void start()
    {
        boost::lock_guard<boost::mutex> lock(_guard);

        if (is_active())
            return; // Already executed.
        if (_interval <= 0)
            return;

        _timer_thread.interrupt();
        _timer_thread.join();

        timer_worker job;
        _timer_thread = boost::thread(job, this);

        _is_active = true;
    };

    void stop()
    {
        boost::lock_guard<boost::mutex> lock(_guard);

        if (!is_active())
            return; // Already executed.

        _timer_thread.interrupt();
        _timer_thread.join();

        _is_active = false;
    };

    inline bool is_active() const { return _is_active; };

    inline int get_interval() const { return _interval; };

    void set_interval(const int msec)
    {
        if (msec <= 0 || _interval == msec)
            return;

        boost::lock_guard<boost::mutex> lock(_guard);
        // Keep timer activity status.
        bool was_active = is_active();

        if (was_active)
            stop();
        // Initialize timer with new interval.
        _interval = msec;

        if (was_active)
            start();
    };

protected:
    friend struct timer_worker;
    // The timer worker thread.
    struct timer_worker
    {
        void operator()(timer* t)
        {
            boost::posix_time::milliseconds duration(t->get_interval());

            try
            {
                while (1)
                {
                    boost::this_thread::sleep<boost::posix_time::milliseconds>(duration);
                    {
                        boost::this_thread::disable_interruption di;
                        {
                            t->_signalTimeout();
                        }
                    }
                }
            }
            catch (boost::thread_interrupted const& )
            {
                // Handle the thread interruption exception.
                // This exception raises on boots::this_thread::interrupt.
            }
        };
    };

protected:
    int             _interval;
    bool            _is_active;

    boost::mutex    _guard;
    boost::thread   _timer_thread;

    // Signal slots
    timeout_slot    _signalTimeout;
};

사용의 예 :

void _test_timer_handler()
{
    std::cout << "_test_timer_handler\n";
}

BOOST_AUTO_TEST_CASE( test_timer )
{
    emtorrus::timer timer;

    BOOST_CHECK(!timer.is_active());
    BOOST_CHECK(timer.get_interval() == 0);

    timer.set_interval(1000);
    timer.connect(_test_timer_handler);

    timer.start();

    BOOST_CHECK(timer.is_active());

    std::cout << "timer test started\n";

    boost::this_thread::sleep<boost::posix_time::milliseconds>(boost::posix_time::milliseconds(5500));

    timer.stop();

    BOOST_CHECK(!timer.is_active());
    BOOST_CHECK(_test_timer_count == 5);
}

해당 함수를 호출하기 직전에 알람을 설정하고 SigalRM을 잡을 수도 있습니다.

블라드, 우수한 게시물! 코드가 컴파일되고 아름답게 작동합니다. 소프트웨어 워치 독 타이머를 구현했습니다. 몇 가지 수정을했습니다.

  • 포인터 붕괴를 방지하려면 신호를 boost :: shared_ptr에 저장하고 타이머 클래스에 대한 약한 포인터 대신 스레드 작업자에게 전달하십시오. 이렇게하면 스레드 작업자가 친구 구조물이 될 필요가 없으며 신호가 메모리에 있음을 보장합니다.
  • 발신자가 작업자 스레드가 주기적인지 또는 만료 후 종료되는지 여부를 선택할 수 있도록 매개 변수 _is_periodic을 추가하십시오.
  • _is_active, _interval 및 _is_periodic in boost :: atomic을 저장하여 스레드-안전 액세스를 허용합니다.
  • 뮤텍스 잠금의 범위를 좁 힙니다.
  • Reset () 메소드를 추가하여 타이머를 "차"하여 만료 신호를 발행하지 못하게합니다.

이러한 변경 사항이 적용된 경우 :

#include <atomic>
#include <boost/signals2.hpp>
#include <boost/thread.hpp>

class IntervalThread
{
    using interval_signal = boost::signals2::signal<void(void)>;

public:
    using interval_slot_t = interval_signal::slot_type;

    IntervalThread(const int interval_ms = 60)
      : _interval_ms(interval_ms),
        _is_active(false),
        _is_periodic(false),
        _signal_expired(new interval_signal()) {};

    inline ~IntervalThread(void) { stop(); };

    boost::signals2::connection connect(const interval_slot_t &subscriber)
    {
        // thread-safe: signals2 obtains a mutex on connect()
        return _signal_expired->connect(subscriber); 
    };

    void start(void)
    {
        if (is_active())
            return; // Already executed.
        if (get_interval_ms() <= 0)
            return;

        boost::lock_guard<boost::mutex> lock(_timer_thread_guard);
        _timer_thread.interrupt();
        _timer_thread.join();

        _timer_thread = boost::thread(timer_worker(),
                static_cast<int>(get_interval_ms()),
                static_cast<bool>(is_periodic()),
                _signal_expired);
        _is_active = true;
    };

    void reset(void)
    {
        if (is_active())
            stop();
        start();
    }

    void stop(void)
    {
        if (!is_active())
            return; // Already executed.

        boost::lock_guard<boost::mutex> lock(_timer_thread_guard);
        _timer_thread.interrupt();
        _timer_thread.join();
        _is_active = false;
    };

    inline bool is_active(void) const { return _is_active; };

    inline int get_interval_ms(void) const { return _interval_ms; };

    void set_interval_ms(const int interval_ms)
    {
        if (interval_ms <= 0 || get_interval_ms() == interval_ms)
            return;

        // Cache timer activity state.
        const bool was_active = is_active();
        // Initialize timer with new interval.
        if (was_active)
            stop();
        _interval_ms = interval_ms;
        if (was_active)
            start();
    };

    inline bool is_periodic(void) const { return _is_periodic; }
    inline void set_periodic(const bool is_periodic = true) { _is_periodic = is_periodic; }

private:
    // The timer worker for the interval thread.
    struct timer_worker {
        void operator()(const int interval_ms, const bool is_periodic, boost::shared_ptr<interval_signal> signal_expired)
        {
            boost::posix_time::milliseconds duration(interval_ms);
            try {
                do {
                    boost::this_thread::sleep<boost::posix_time::milliseconds>(duration);
                    {
                        boost::this_thread::disable_interruption di;
                        signal_expired->operator()();
                    }
                } while (is_periodic);
            } catch (const boost::thread_interrupted &) {
                // IntervalThread start(), stop() and reset() throws boost::this_thread::interrupt,
                // which is expected since this thread is interrupted. No action neccessary.
            }
        };
    };

    std::atomic<int> _interval_ms;  // Interval, in ms
    std::atomic<bool> _is_active;   // Is the timed interval active?
    std::atomic<bool> _is_periodic; // Is the timer periodic?

    boost::mutex _timer_thread_guard;
    boost::thread _timer_thread;

    // The signal to call on interval expiration.
    boost::shared_ptr<interval_signal> _signal_expired;
};
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top