Boost Signals2 및 스레드를 사용하여 C ++에서 소프트웨어 Watchdog 타이머 스레드를 만들 수 있습니까?
-
06-07-2019 - |
문제
나는 현재 단일 스레드 응용 프로그램에서 다른 사람의 라이브러리에서 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;
};
제휴하지 않습니다 StackOverflow