fixed GH #2058: Synchronization issue in Poco::Util::Timer at destruction

This commit is contained in:
Günter Obiltschnig
2018-03-06 17:33:02 +01:00
parent f352f61e5b
commit d73bb2ea86
3 changed files with 86 additions and 33 deletions

View File

@@ -32,18 +32,18 @@ public:
_queue(queue) _queue(queue)
{ {
} }
~TimerNotification() ~TimerNotification()
{ {
} }
virtual bool execute() = 0; virtual bool execute() = 0;
Poco::TimedNotificationQueue& queue() Poco::TimedNotificationQueue& queue()
{ {
return _queue; return _queue;
} }
private: private:
Poco::TimedNotificationQueue& _queue; Poco::TimedNotificationQueue& _queue;
}; };
@@ -56,11 +56,11 @@ public:
TimerNotification(queue) TimerNotification(queue)
{ {
} }
~StopNotification() ~StopNotification()
{ {
} }
bool execute() bool execute()
{ {
queue().clear(); queue().clear();
@@ -76,23 +76,36 @@ public:
TimerNotification(queue) TimerNotification(queue)
{ {
} }
~CancelNotification() ~CancelNotification()
{ {
} }
bool execute() bool execute()
{ {
// Check if there's a StopNotification pending.
Poco::AutoPtr<TimerNotification> pNf = static_cast<TimerNotification*>(queue().dequeueNotification());
while (pNf)
{
if (pNf.cast<StopNotification>())
{
queue().clear();
_finished.set();
return false;
}
pNf = static_cast<TimerNotification*>(queue().dequeueNotification());
}
queue().clear(); queue().clear();
_finished.set(); _finished.set();
return true; return true;
} }
void wait() void wait()
{ {
_finished.wait(); _finished.wait();
} }
private: private:
Poco::Event _finished; Poco::Event _finished;
}; };
@@ -106,16 +119,16 @@ public:
_pTask(pTask) _pTask(pTask)
{ {
} }
~TaskNotification() ~TaskNotification()
{ {
} }
TimerTask::Ptr task() TimerTask::Ptr task()
{ {
return _pTask; return _pTask;
} }
bool execute() bool execute()
{ {
if (!_pTask->isCancelled()) if (!_pTask->isCancelled())
@@ -140,7 +153,7 @@ public:
} }
return true; return true;
} }
private: private:
TimerTask::Ptr _pTask; TimerTask::Ptr _pTask;
}; };
@@ -154,13 +167,13 @@ public:
_interval(interval) _interval(interval)
{ {
} }
~PeriodicTaskNotification() ~PeriodicTaskNotification()
{ {
} }
bool execute() bool execute()
{ {
TaskNotification::execute(); TaskNotification::execute();
if (!task()->isCancelled()) if (!task()->isCancelled())
@@ -172,9 +185,9 @@ public:
queue().enqueueNotification(this, nextExecution); queue().enqueueNotification(this, nextExecution);
duplicate(); duplicate();
} }
return true; return true;
} }
private: private:
long _interval; long _interval;
}; };
@@ -189,13 +202,13 @@ public:
_nextExecution(clock) _nextExecution(clock)
{ {
} }
~FixedRateTaskNotification() ~FixedRateTaskNotification()
{ {
} }
bool execute() bool execute()
{ {
TaskNotification::execute(); TaskNotification::execute();
if (!task()->isCancelled()) if (!task()->isCancelled())
@@ -206,9 +219,9 @@ public:
queue().enqueueNotification(this, _nextExecution); queue().enqueueNotification(this, _nextExecution);
duplicate(); duplicate();
} }
return true; return true;
} }
private: private:
long _interval; long _interval;
Poco::Clock _nextExecution; Poco::Clock _nextExecution;
@@ -241,7 +254,7 @@ Timer::~Timer()
} }
} }
void Timer::cancel(bool wait) void Timer::cancel(bool wait)
{ {
Poco::AutoPtr<CancelNotification> pNf = new CancelNotification(_queue); Poco::AutoPtr<CancelNotification> pNf = new CancelNotification(_queue);
@@ -266,7 +279,7 @@ void Timer::schedule(TimerTask::Ptr pTask, Poco::Clock clock)
_queue.enqueueNotification(new TaskNotification(_queue, pTask), clock); _queue.enqueueNotification(new TaskNotification(_queue, pTask), clock);
} }
void Timer::schedule(TimerTask::Ptr pTask, long delay, long interval) void Timer::schedule(TimerTask::Ptr pTask, long delay, long interval)
{ {
Poco::Clock clock; Poco::Clock clock;
@@ -288,7 +301,7 @@ void Timer::schedule(TimerTask::Ptr pTask, Poco::Clock clock, long interval)
_queue.enqueueNotification(new PeriodicTaskNotification(_queue, pTask, interval), clock); _queue.enqueueNotification(new PeriodicTaskNotification(_queue, pTask, interval), clock);
} }
void Timer::scheduleAtFixedRate(TimerTask::Ptr pTask, long delay, long interval) void Timer::scheduleAtFixedRate(TimerTask::Ptr pTask, long delay, long interval)
{ {
Poco::Clock clock; Poco::Clock clock;

View File

@@ -197,18 +197,18 @@ void TimerTest::testScheduleAtFixedRate()
void TimerTest::testCancel() void TimerTest::testCancel()
{ {
Timer timer; Timer timer;
Timestamp time; Timestamp time;
TimerTask::Ptr pTask = new TimerTaskAdapter<TimerTest>(*this, &TimerTest::onTimer); TimerTask::Ptr pTask = new TimerTaskAdapter<TimerTest>(*this, &TimerTest::onTimer);
assert (pTask->lastExecution() == 0); assert (pTask->lastExecution() == 0);
timer.scheduleAtFixedRate(pTask, 5000, 5000); timer.scheduleAtFixedRate(pTask, 5000, 5000);
pTask->cancel(); pTask->cancel();
assert (pTask->isCancelled()); assert (pTask->isCancelled());
try try
{ {
timer.scheduleAtFixedRate(pTask, 5000, 5000); timer.scheduleAtFixedRate(pTask, 5000, 5000);
@@ -224,6 +224,42 @@ void TimerTest::testCancel()
} }
void TimerTest::testCancelAllStop()
{
{
Timer timer;
TimerTask::Ptr pTask = new TimerTaskAdapter<TimerTest>(*this, &TimerTest::onTimer);
timer.scheduleAtFixedRate(pTask, 5000, 5000);
Poco::Thread::sleep(100);
timer.cancel(false);
}
assert (true); // don't hang
}
void TimerTest::testCancelAllWaitStop()
{
{
Timer timer;
TimerTask::Ptr pTask = new TimerTaskAdapter<TimerTest>(*this, &TimerTest::onTimer);
timer.scheduleAtFixedRate(pTask, 5000, 5000);
Poco::Thread::sleep(100);
timer.cancel(true);
}
assert (true); // don't hang
}
void TimerTest::setUp() void TimerTest::setUp()
{ {
} }
@@ -252,6 +288,8 @@ CppUnit::Test* TimerTest::suite()
CppUnit_addTest(pSuite, TimerTest, testScheduleIntervalClock); CppUnit_addTest(pSuite, TimerTest, testScheduleIntervalClock);
CppUnit_addTest(pSuite, TimerTest, testScheduleAtFixedRate); CppUnit_addTest(pSuite, TimerTest, testScheduleAtFixedRate);
CppUnit_addTest(pSuite, TimerTest, testCancel); CppUnit_addTest(pSuite, TimerTest, testCancel);
CppUnit_addTest(pSuite, TimerTest, testCancelAllStop);
CppUnit_addTest(pSuite, TimerTest, testCancelAllWaitStop);
return pSuite; return pSuite;
} }

View File

@@ -33,6 +33,8 @@ public:
void testScheduleIntervalTimestamp(); void testScheduleIntervalTimestamp();
void testScheduleIntervalClock(); void testScheduleIntervalClock();
void testCancel(); void testCancel();
void testCancelAllStop();
void testCancelAllWaitStop();
void setUp(); void setUp();
void tearDown(); void tearDown();