Timer: smaller glitches with 'sleep time remainder', TimerTest: proper close / wait for Timer enabled applications example

git-svn-id: svn://ultimatepp.org/upp/trunk@2549 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
kohait 2010-07-19 11:23:24 +00:00
parent 335799d2c9
commit cd8510db6e
6 changed files with 58 additions and 13 deletions

View file

@ -4,7 +4,7 @@
Timer::Timer() Timer::Timer()
{ {
granularity = 2; granularity = 10;
run = true; run = true;
t.Run(THISBACK(TimerThread)); t.Run(THISBACK(TimerThread));
} }
@ -73,7 +73,7 @@ void Timer::KillTimeCallback(void *id) {
KillTimeCallbacks(id); KillTimeCallbacks(id);
} }
void Timer::TimerProc(dword time) void Timer::TimerProc(dword time, int & leftsleep)
{ {
if(IsPanicMode()) if(IsPanicMode())
return; return;
@ -87,7 +87,7 @@ void Timer::TimerProc(dword time)
// sTimerLock.Leave(); // sTimerLock.Leave();
// //*** // //***
// sTimerLock.Enter(); // sTimerLock.Enter();
while(list->GetNext() != list && list->GetNext()->time < time) { while(list->GetNext() != list && ((leftsleep = (list->GetNext()->time - time)) <= 0)) {
TimeEvent *e = list->GetNext(); TimeEvent *e = list->GetNext();
e->Unlink(); e->Unlink();
if(e->delay < 0) if(e->delay < 0)
@ -98,6 +98,7 @@ void Timer::TimerProc(dword time)
delete e; delete e;
} }
sTimerLock.Leave(); sTimerLock.Leave();
if(leftsleep < 0) leftsleep = granularity; //if last done has been processed and no more in queue, ensure good sleep
} }
//SAME API AS IN Ctrl //SAME API AS IN Ctrl
@ -145,9 +146,11 @@ void Timer::SetTimerGranularity(int ms)
void Timer::TimerThread() void Timer::TimerThread()
{ {
int leftsleep;
while(run) while(run)
{ {
TimerProc(GetTickCount()); leftsleep = granularity;
Sleep(granularity); //granularity TimerProc(GetTickCount(), leftsleep);
Sleep(min(granularity, leftsleep));
} }
} }

View file

@ -39,7 +39,7 @@ private:
void KillTimeCallbacks(void *id, void *idlim); void KillTimeCallbacks(void *id, void *idlim);
bool ExistsTimeCallback(void *id); bool ExistsTimeCallback(void *id);
void KillTimeCallback(void *id); void KillTimeCallback(void *id);
void TimerProc(dword time); void TimerProc(dword time, int & leftsleep);
void KillTimeCallbacks(void *id); void KillTimeCallbacks(void *id);

View file

@ -18,12 +18,14 @@ things wont get to execution, until a current task is finished,
and the timer queue can check whether time has come for the next and the timer queue can check whether time has come for the next
task.]&] task.]&]
[s0;2 &] [s0;2 &]
[s0;i150;O0; [2 Because of it, the timing is not as accurate as maybe [s0;i150;O0; [2 Thus, the timing is not as accurate as maybe desired
desired and can have `"timer glitches/jitter`", depending on and can have `"timer glitches/jitter`", depending on work load..]&]
work load..]&]
[s0;2 &] [s0;2 &]
[s0;i150;O0; [2 Favorite use is to schedule some `*non`*`-timing`-critical [s0;i150;O0; [2 Favorite use is to schedule some `*non`*`-timing`-critical
work for `"somewhere`-around`-in`-the`-future`".]&] work for `"somewhere`-around`-in`-the`-future`", like i.e. observe
some not too strict timing constraints in custom communication
protocols (answer needs to come in within X time, keep alive
messages..)]&]
[s0;2 &] [s0;2 &]
[s0;i150;O0; [2 For timing critical stuff, consider using OS native [s0;i150;O0; [2 For timing critical stuff, consider using OS native
timer means, for WIN32 SetTimer (in windowing environment, using timer means, for WIN32 SetTimer (in windowing environment, using

View file

@ -14,11 +14,16 @@ class TimerTest : public WithLayout<TopWindow> {
public: public:
typedef TimerTest CLASSNAME; typedef TimerTest CLASSNAME;
TimerTest(); TimerTest();
~TimerTest();
void Close0();
virtual void Close();
void Info(const String & s); void Info(const String & s);
void Test(); void Test();
private: private:
Timer t; Timer t;
Atomic demo;
}; };
#endif #endif

View file

@ -1,3 +1,5 @@
description "Test for Timer package\377";
uses uses
CtrlLib, CtrlLib,
Timer; Timer;

View file

@ -3,12 +3,17 @@
#define REPEAT_TEST #define REPEAT_TEST
TimerTest::TimerTest() TimerTest::TimerTest()
: demo(0)
{ {
CtrlLayout(*this, "Window title"); CtrlLayout(*this, "Window title");
int a = AtomicInc(demo);
ASSERT(a==1); //preload, 1 means running demo mode, 2 means a cb is executing
#ifdef REPEAT_TEST #ifdef REPEAT_TEST
t.SetTimeCallback(-1000, THISBACK(Test), 0); t.SetTimeCallback(-100, THISBACK(Test), (int)this);
#else #else
PostCallback(THISBACK(Test)); t.SetTimeCallback(0, THISBACK(Test), (int)this);
#endif #endif
} }
@ -20,13 +25,41 @@ void TimerTest::Info(const String & s)
void TimerTest::Test() void TimerTest::Test()
{ {
int a = AtomicInc(demo);
ASSERT(a==2);
Info("O"); Info("O");
RLOG("O");
a = AtomicDec(demo);
if(a<=0)
return;
ASSERT(a>=0);
#ifdef REPEAT_TEST #ifdef REPEAT_TEST
#else #else
t.SetTimeCallback(1000, THISBACK(Test), 0); t.SetTimeCallback(100, THISBACK(Test), (int)this);
#endif #endif
} }
void TimerTest::Close()
{
t.KillTimeCallback((int)this);
int a = AtomicDec(demo);
Thread::Start(THISBACK(Close0));
}
void TimerTest::Close0()
{
while(AtomicRead(demo) > 0) Sleep(1);
ASSERT(AtomicRead(demo)==0);
TopWindow::Close();
}
TimerTest::~TimerTest()
{
}
GUI_APP_MAIN GUI_APP_MAIN
{ {
TimerTest().Run(); TimerTest().Run();