Frage

Ich betreiben Funktion Foo von jemandem anderer Bibliothek in einer Singlethread-Anwendung zur Zeit. Die meiste Zeit, mache ich einen Anruf an Foo und es ist wirklich schnell, manchmal mache ich einen Anruf an Foo und es dauert ewig. Ich bin kein geduldiger Mensch, wenn Foo ewig dauern wird, ich will die Ausführung von Foo stoppen und es nicht mit diesen Argumenten aufrufen.

Was ist der beste Weg ist, Foo in einer kontrollierten Art und Weise zu nennen (meine aktuelle Umgebung ist POSIX / C ++), so dass ich die Ausführung nach einer bestimmten Anzahl von Sekunden zu stoppen. Ich fühle mich wie das Richtiges zu tun hier ist einen zweiten Thread zu erstellen Foo zu nennen, während in meinem Haupt-Thread ich eine Timer-Funktion erstellen, die schließlich den zweiten Thread signalisiert, wenn es aus der Zeit ausgeführt wird.

Gibt es eine andere, mehr apt-Modell (und Lösung)? Wenn nicht, würde die Erhöhung Signals2 Bibliothek und Themen der Trick?

War es hilfreich?

Lösung

Sie können Foo rufen auf einem zweiten Thread mit einem Timeout. Zum Beispiel:

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

Andere Tipps

Sie können die folgende Klasse verwenden:

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

Ein Beispiel für die Verwendung:

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

Sie können auch einen Alarm direkt vor diese Funktion aufrufen, und fangen SIGALRM gesetzt.

Vlad, sehr guter Beitrag! Ihr Code kompiliert und funktioniert wunderbar. Ich implementiert einen Software-Watchdog-Timer mit ihm. Ich habe ein paar Änderungen:

  • Zeiger Zerfall zu verhindern, speichern Sie das Signal in boost :: shared_ptr und diese Arbeiter auf den Faden passieren anstelle eines schwachen Zeiger auf die Timer-Klasse. Dadurch entfällt die Notwendigkeit für den Thread Arbeiter ein Freund struct zu sein und garantiert das Signal im Speicher vorhanden ist.
  • Fügen Sie Parameter _is_periodic den Anrufer zu ermöglichen, auszuwählen, ob der Arbeiter-Thread periodisch ist oder wenn es endet nach Ablauf.
  • Shop _is_active, _interval und _is_periodic in boost :: Atom Thread-sicheren Zugang zu ermöglichen.
  • Grenzen Sie den Umfang der Mutex-Verriegelung.
  • Fügen Sie reset () Methode der Timer auf "Kick", es aus der Ausgabe der Ablaufsignal zu verhindern.

Mit diesen Änderungen angewandt:

#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;
};
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top