我可以使用 Boost Signals2 和 Threads 在 C++ 中创建软件看门狗定时器线程吗?
Posted
技术标签:
【中文标题】我可以使用 Boost Signals2 和 Threads 在 C++ 中创建软件看门狗定时器线程吗?【英文标题】:Can I create a software watchdog timer thread in C++ using Boost Signals2 and Threads? 【发布时间】:2010-11-04 04:03:47 【问题描述】:我目前正在单线程应用程序中从其他人的库中运行函数 Foo。大多数时候,我打电话给 Foo,它真的很快,有时,我打电话给 Foo,它需要很长时间。我不是一个有耐心的人,如果 Foo 要永远占用,我想停止执行 Foo 并且不使用这些参数调用它。
以受控方式调用 Foo 的最佳方法是什么(我当前的环境是 POSIX/C++),这样我可以在一定秒数后停止执行。我觉得在这里做的正确的事情是创建第二个线程来调用 Foo,而在我的主线程中我创建了一个计时器函数,如果第二个线程超时,它最终会发出信号。
还有其他更合适的模型(和解决方案)吗?如果没有,Boost 的 Signals2 库和 Threads 能解决问题吗?
【问题讨论】:
【参考方案1】:您可以在超时的第二个线程上调用 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;
【讨论】:
澄清一下,timed_join
不会 如果达到超时,则停止 Foo()
线程的执行,正如我认为 Aron 所要求的那样。相反,调用者只会知道在达到超时时Foo()
线程仍在运行。【参考方案2】:
您可以使用以下类:
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);
【讨论】:
【参考方案3】:您还可以在调用该函数之前设置警报,并捕获 SIGALRM。
【讨论】:
【参考方案4】:弗拉德,出色的帖子!您的代码已编译并且运行良好。我用它实现了一个软件看门狗定时器。我做了一些修改:
为防止指针衰减,请将信号存储在 boost::shared_ptr 中,并将其传递给线程工作者,而不是指向计时器类的弱指针。这消除了线程工作者成为友元结构的需要,并保证信号在内存中。 添加参数 _is_periodic 以允许调用者选择工作线程是周期性的还是到期后终止。 将 _is_active、_interval 和 _is_periodic 存储在 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;
;
【讨论】:
以上是关于我可以使用 Boost Signals2 和 Threads 在 C++ 中创建软件看门狗定时器线程吗?的主要内容,如果未能解决你的问题,请参考以下文章
使用 boost::signals2 和卸载 DLL 时访问冲突