improved Lambda support

This commit is contained in:
Günter Obiltschnig
2020-01-26 08:41:22 +01:00
parent 14e58b7fea
commit 958387b6ba
6 changed files with 122 additions and 43 deletions

View File

@@ -154,12 +154,19 @@ public:
/// Starts the thread with the given target and parameter. /// Starts the thread with the given target and parameter.
template <class Functor> template <class Functor>
void startFunc(Functor fn) void startFunc(const Functor& fn)
/// Starts the thread with the given functor object or lambda. /// Starts the thread with the given functor object or lambda.
{ {
startImpl(new FunctorRunnable<Functor>(fn)); startImpl(new FunctorRunnable<Functor>(fn));
} }
template <class Functor>
void startFunc(Functor&& fn)
/// Starts the thread with the given functor object or lambda.
{
startImpl(new FunctorRunnable<Functor>(std::move(fn)));
}
void join(); void join();
/// Waits until the thread completes execution. /// Waits until the thread completes execution.
/// If multiple threads try to join the same /// If multiple threads try to join the same
@@ -242,6 +249,11 @@ protected:
{ {
} }
FunctorRunnable(Functor&& functor):
_functor(std::move(functor))
{
}
~FunctorRunnable() ~FunctorRunnable()
{ {
} }

View File

@@ -36,7 +36,7 @@ public:
MyRunnable(): _ran(false) MyRunnable(): _ran(false)
{ {
} }
void run() void run()
{ {
Thread* pThread = Thread::current(); Thread* pThread = Thread::current();
@@ -45,22 +45,22 @@ public:
_ran = true; _ran = true;
_event.wait(); _event.wait();
} }
bool ran() const bool ran() const
{ {
return _ran; return _ran;
} }
const std::string& threadName() const const std::string& threadName() const
{ {
return _threadName; return _threadName;
} }
void notify() void notify()
{ {
_event.set(); _event.set();
} }
static void staticFunc() static void staticFunc()
{ {
++_staticVar; ++_staticVar;
@@ -96,17 +96,17 @@ public:
NonJoinRunnable() : _finished(false) NonJoinRunnable() : _finished(false)
{ {
} }
void run() void run()
{ {
_finished = true; _finished = true;
} }
bool finished() const bool finished() const
{ {
return _finished; return _finished;
} }
private: private:
bool _finished; bool _finished;
}; };
@@ -264,12 +264,12 @@ void ThreadTest::testNotJoin()
Thread thread; Thread thread;
NonJoinRunnable r; NonJoinRunnable r;
thread.start(r); thread.start(r);
while (!r.finished()) while (!r.finished())
{ {
Thread::sleep(10); Thread::sleep(10);
} }
Thread::sleep(100); Thread::sleep(100);
assertTrue (!thread.isRunning()); assertTrue (!thread.isRunning());
} }
@@ -383,20 +383,19 @@ void ThreadTest::testThreadFunctor()
assertTrue (!thread.isRunning()); assertTrue (!thread.isRunning());
#if __cplusplus >= 201103L
Thread thread2; Thread thread2;
assertTrue (!thread2.isRunning()); assertTrue (!thread2.isRunning());
MyRunnable::_staticVar = 0; MyRunnable::_staticVar = 0;
thread.startFunc([] () {MyRunnable::_staticVar++;}); thread.startFunc([] ()
{
MyRunnable::_staticVar++;
});
thread.join(); thread.join();
assertTrue (1 == MyRunnable::_staticVar); assertTrue (1 == MyRunnable::_staticVar);
assertTrue (!thread2.isRunning()); assertTrue (!thread2.isRunning());
#endif
} }

View File

@@ -30,9 +30,9 @@ namespace Util {
class Util_API Timer: protected Poco::Runnable class Util_API Timer: protected Poco::Runnable
/// A Timer allows to schedule tasks (TimerTask objects) for future execution /// A Timer allows to schedule tasks (TimerTask objects) for future execution
/// in a background thread. Tasks may be scheduled for one-time execution, /// in a background thread. Tasks may be scheduled for one-time execution,
/// or for repeated execution at regular intervals. /// or for repeated execution at regular intervals.
/// ///
/// The Timer object creates a thread that executes all scheduled tasks /// The Timer object creates a thread that executes all scheduled tasks
/// sequentially. Therefore, tasks should complete their work as quickly /// sequentially. Therefore, tasks should complete their work as quickly
@@ -41,20 +41,29 @@ class Util_API Timer: protected Poco::Runnable
/// Timer is safe for multithreaded use - multiple threads can schedule /// Timer is safe for multithreaded use - multiple threads can schedule
/// new tasks simultaneously. /// new tasks simultaneously.
/// ///
/// Via the func() helper function template, a functor or
/// lambda can be used as timer task:
///
/// timer.schedule(Timer::func([]()
/// {
/// std::cout << "Timer!\n";
/// }),
/// Poco::Clock());
///
/// Acknowledgement: The interface of this class has been inspired by /// Acknowledgement: The interface of this class has been inspired by
/// the java.util.Timer class from Java 1.3. /// the java.util.Timer class from Java 1.3.
{ {
public: public:
Timer(); Timer();
/// Creates the Timer. /// Creates the Timer.
explicit Timer(Poco::Thread::Priority priority); explicit Timer(Poco::Thread::Priority priority);
/// Creates the Timer, using a timer thread with /// Creates the Timer, using a timer thread with
/// the given priority. /// the given priority.
~Timer(); ~Timer();
/// Destroys the Timer, cancelling all pending tasks. /// Destroys the Timer, cancelling all pending tasks.
void cancel(bool wait = false); void cancel(bool wait = false);
/// Cancels all pending tasks. /// Cancels all pending tasks.
/// ///
@@ -65,7 +74,7 @@ public:
/// task queue will be purged as soon as the currently /// task queue will be purged as soon as the currently
/// running task finishes. If wait is true, waits /// running task finishes. If wait is true, waits
/// until the queue has been purged. /// until the queue has been purged.
void schedule(TimerTask::Ptr pTask, Poco::Timestamp time); void schedule(TimerTask::Ptr pTask, Poco::Timestamp time);
/// Schedules a task for execution at the specified time. /// Schedules a task for execution at the specified time.
/// ///
@@ -84,7 +93,7 @@ public:
/// ///
/// If the time lies in the past, the task is executed /// If the time lies in the past, the task is executed
/// immediately. /// immediately.
void schedule(TimerTask::Ptr pTask, long delay, long interval); void schedule(TimerTask::Ptr pTask, long delay, long interval);
/// Schedules a task for periodic execution. /// Schedules a task for periodic execution.
/// ///
@@ -112,12 +121,12 @@ public:
/// The task is first executed at the given time. /// The task is first executed at the given time.
/// Subsequently, the task is executed periodically with /// Subsequently, the task is executed periodically with
/// the given interval in milliseconds between invocations. /// the given interval in milliseconds between invocations.
void scheduleAtFixedRate(TimerTask::Ptr pTask, long delay, long interval); void scheduleAtFixedRate(TimerTask::Ptr pTask, long delay, long interval);
/// Schedules a task for periodic execution at a fixed rate. /// Schedules a task for periodic execution at a fixed rate.
/// ///
/// The task is first executed after the given delay. /// The task is first executed after the given delay.
/// Subsequently, the task is executed periodically /// Subsequently, the task is executed periodically
/// every number of milliseconds specified by interval. /// every number of milliseconds specified by interval.
/// ///
/// If task execution takes longer than the given interval, /// If task execution takes longer than the given interval,
@@ -127,7 +136,7 @@ public:
/// Schedules a task for periodic execution at a fixed rate. /// Schedules a task for periodic execution at a fixed rate.
/// ///
/// The task is first executed at the given time. /// The task is first executed at the given time.
/// Subsequently, the task is executed periodically /// Subsequently, the task is executed periodically
/// every number of milliseconds specified by interval. /// every number of milliseconds specified by interval.
/// ///
/// If task execution takes longer than the given interval, /// If task execution takes longer than the given interval,
@@ -144,20 +153,36 @@ public:
/// Schedules a task for periodic execution at a fixed rate. /// Schedules a task for periodic execution at a fixed rate.
/// ///
/// The task is first executed at the given time. /// The task is first executed at the given time.
/// Subsequently, the task is executed periodically /// Subsequently, the task is executed periodically
/// every number of milliseconds specified by interval. /// every number of milliseconds specified by interval.
/// ///
/// If task execution takes longer than the given interval, /// If task execution takes longer than the given interval,
/// further executions are delayed. /// further executions are delayed.
template <typename Fn>
static TimerTask::Ptr func(const Fn& fn)
/// Helper function template to use a functor or lambda
/// with Timer::schedule() and Timer::scheduleAtFixedRate().
{
return new TimerFunc<Fn>(fn);
}
template <typename Fn>
static TimerTask::Ptr func(Fn&& fn)
/// Helper function template to use a functor or lambda
/// with Timer::schedule() and Timer::scheduleAtFixedRate().
{
return new TimerFunc<Fn>(std::move(fn));
}
protected: protected:
void run(); void run();
static void validateTask(const TimerTask::Ptr& pTask); static void validateTask(const TimerTask::Ptr& pTask);
private: private:
Timer(const Timer&); Timer(const Timer&);
Timer& operator = (const Timer&); Timer& operator = (const Timer&);
Poco::TimedNotificationQueue _queue; Poco::TimedNotificationQueue _queue;
Poco::Thread _thread; Poco::Thread _thread;
}; };

View File

@@ -30,7 +30,7 @@ namespace Util {
class Util_API TimerTask: public Poco::RefCountedObject, public Poco::Runnable class Util_API TimerTask: public Poco::RefCountedObject, public Poco::Runnable
/// A task that can be scheduled for one-time or /// A task that can be scheduled for one-time or
/// repeated execution by a Timer. /// repeated execution by a Timer.
/// ///
/// This is an abstract class. Subclasses must override the run() member /// This is an abstract class. Subclasses must override the run() member
@@ -38,45 +38,71 @@ class Util_API TimerTask: public Poco::RefCountedObject, public Poco::Runnable
{ {
public: public:
using Ptr = Poco::AutoPtr<TimerTask>; using Ptr = Poco::AutoPtr<TimerTask>;
TimerTask(); TimerTask();
/// Creates the TimerTask. /// Creates the TimerTask.
void cancel(); void cancel();
/// Cancels the execution of the timer. /// Cancels the execution of the timer.
/// If the task has been scheduled for one-time execution and has /// If the task has been scheduled for one-time execution and has
/// not yet run, or has not yet been scheduled, it will never run. /// not yet run, or has not yet been scheduled, it will never run.
/// If the task has been scheduled for repeated execution, it will never /// If the task has been scheduled for repeated execution, it will never
/// run again. If the task is running when this call occurs, the task /// run again. If the task is running when this call occurs, the task
/// will run to completion, but will never run again. /// will run to completion, but will never run again.
/// ///
/// Warning: A TimerTask that has been cancelled must not be scheduled again. /// Warning: A TimerTask that has been cancelled must not be scheduled again.
/// An attempt to do so results in a Poco::Util::IllegalStateException being thrown. /// An attempt to do so results in a Poco::Util::IllegalStateException being thrown.
bool isCancelled() const; bool isCancelled() const;
/// Returns true iff the TimerTask has been cancelled by a call /// Returns true iff the TimerTask has been cancelled by a call
/// to cancel(). /// to cancel().
Poco::Timestamp lastExecution() const; Poco::Timestamp lastExecution() const;
/// Returns the time of the last execution of the timer task. /// Returns the time of the last execution of the timer task.
/// ///
/// Returns 0 if the timer has never been executed. /// Returns 0 if the timer has never been executed.
protected: protected:
~TimerTask(); ~TimerTask();
/// Destroys the TimerTask. /// Destroys the TimerTask.
private: private:
TimerTask(const TimerTask&); TimerTask(const TimerTask&);
TimerTask& operator = (const TimerTask&); TimerTask& operator = (const TimerTask&);
Poco::Timestamp _lastExecution; Poco::Timestamp _lastExecution;
bool _isCancelled; bool _isCancelled;
friend class TaskNotification; friend class TaskNotification;
}; };
template <typename Fn>
class TimerFunc: public TimerTask
/// A simple adapter that allows using a functor or lambda
/// with Poco::Util::Timer, used by timerFunc().
{
public:
explicit TimerFunc(const Fn& fn):
_fn(fn)
{
}
explicit TimerFunc(Fn&& fn):
_fn(std::move(fn))
{
}
void run()
{
_fn();
}
private:
Fn _fn;
};
// //
// inlines // inlines
// //

View File

@@ -260,6 +260,21 @@ void TimerTest::testCancelAllWaitStop()
} }
void TimerTest::testFunc()
{
Timer timer;
int count = 0;
timer.schedule(Timer::func([&count]()
{
count++;
}), Poco::Clock());
Poco::Thread::sleep(100);
assertTrue (count == 1);
}
void TimerTest::setUp() void TimerTest::setUp()
{ {
} }
@@ -290,6 +305,7 @@ CppUnit::Test* TimerTest::suite()
CppUnit_addTest(pSuite, TimerTest, testCancel); CppUnit_addTest(pSuite, TimerTest, testCancel);
CppUnit_addTest(pSuite, TimerTest, testCancelAllStop); CppUnit_addTest(pSuite, TimerTest, testCancelAllStop);
CppUnit_addTest(pSuite, TimerTest, testCancelAllWaitStop); CppUnit_addTest(pSuite, TimerTest, testCancelAllWaitStop);
CppUnit_addTest(pSuite, TimerTest, testFunc);
return pSuite; return pSuite;
} }

View File

@@ -35,6 +35,7 @@ public:
void testCancel(); void testCancel();
void testCancelAllStop(); void testCancelAllStop();
void testCancelAllWaitStop(); void testCancelAllWaitStop();
void testFunc();
void setUp(); void setUp();
void tearDown(); void tearDown();