2009-06-18 9 views
9

मैं वर्तमान में एकल-थ्रेडेड एप्लिकेशन में किसी और की लाइब्रेरी से फ़ू फ़ू चला रहा हूं। ज्यादातर समय, मैं फू को फोन करता हूं और यह वास्तव में तेज़ है, कुछ बार, मैं फू को फोन करता हूं और यह हमेशा के लिए लेता है। मैं एक मरीज आदमी नहीं हूं, अगर फू हमेशा के लिए ले जा रहा है, तो मैं फू के निष्पादन को रोकना चाहता हूं और उन तर्कों के साथ इसे कॉल नहीं करना चाहता हूं।क्या मैं बूस्ट सिग्नल 2 और थ्रेड का उपयोग कर सी ++ में सॉफ़्टवेयर वॉचडॉग टाइमर थ्रेड बना सकता हूं?

सबसे अच्छा तरीका है एक नियंत्रित तरीके से फू कॉल करने के लिए क्या है कि मैं सेकंड की एक निश्चित संख्या के बाद निष्पादन रोक सकता है इस तरह के (मेरे वर्तमान वातावरण POSIX/C++ है)। मुझे लगता है कि यहां करने के लिए सही बात यह है कि फू को कॉल करने के लिए दूसरा थ्रेड बनाना है, जबकि मेरे मुख्य धागे में मैं एक टाइमर फ़ंक्शन बनाता हूं जो अंततः दूसरे थ्रेड को सिग्नल करेगा यदि यह समय से बाहर हो जाता है।

वहाँ एक और है, और अधिक उपयुक्त मॉडल (और समाधान) है? यदि नहीं, तो बूस्ट की सिग्नल 2 लाइब्रेरी और थ्रेड्स चाल चलेंगे?

उत्तर

10

आप समय समाप्त के साथ एक दूसरे धागे पर फू कॉल कर सकते हैं। उदाहरण के लिए:

#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; 
} 
+1

बस स्पष्ट करने के लिए, 'timed_join' * * बंद नहीं होगा' फू() 'धागा को फांसी अगर समय समाप्ति तक पहुँच जाता है, के रूप में मैंने सोचा था कि एरन कहा था के लिये। इसके बजाए, कॉलर केवल यह जान लेगा कि टाइमआउट पहुंचने पर 'Foo() 'थ्रेड अभी भी चल रहा था। – pilcrow

2

तुम भी सही है कि समारोह कॉल करने से पहले एक अलार्म सेट कर सकते हैं, और पकड़ SIGALRM।

6

आप निम्नलिखित वर्ग का उपयोग कर सकते हैं:

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); 
} 
1

Vlad, उत्कृष्ट पोस्ट! आपका कोड संकलित और खूबसूरती से काम करता है। मैंने इसके साथ एक सॉफ्टवेयर वॉचडॉग टाइमर लागू किया।

  • , सूचक क्षय को रोकने बढ़ावा :: shared_ptr में संकेत की दुकान और धागा कार्यकर्ता के बजाय टाइमर वर्ग के लिए एक कमजोर सूचक को यह पारित करने के लिए: मैं कुछ सुधार किए हैं। यह थ्रेड कार्यकर्ता की मित्र संरचना होने की आवश्यकता को समाप्त करता है और संकेत देता है कि सिग्नल स्मृति में है।
  • जोड़ें पैरामीटर _is_periodic फोन करने वाले का चयन करने के लिए किया जाए या नहीं कार्यकर्ता धागा समय-समय पर है या यह समाप्ति के बाद समाप्त हो जाता है, तो अनुमति देने के लिए।
  • स्टोर _is_active, _interval और बढ़ावा :: धागे की सुरक्षित उपयोग की अनुमति परमाणु में _is_periodic।
  • म्यूटेक्स लॉकिंग के दायरे को संक्षिप्त करें।
  • टाइमर को "किक" करने के लिए रीसेट() विधि जोड़ें, इसे समाप्ति सिग्नल जारी करने से रोकें।

इन परिवर्तनों के साथ लागू किया:

#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; 
}; 
संबंधित मुद्दे