Basics overview part II: Timers, Threads and Critical Sections



	

1. Timers

NUI provides two ways for working with timers (Please note that the first timer sample code uses nuiTimer while the second one uses nglTimer):

1.1) using a nuiTimer instance

 1 //**************************************
 2 // declare the timer in your class
 3 class MyObject: public MyParent
 4 {
 5   [...]
 6 private:
 7 
 8   bool OnTick(const nuiEvent& rEvent); // timer event receiver
 9   nuiTimer mTimer;
10 
11   double mStartTime;
12   nuiEventSink<MyObject> mEventSink;
13 };
14 
15 //**************************************
16 // init the timer in the object constructor, giving the timer period in seconds
17 MyObject::MyObject() 
18 : MyParent(), mTimer(0.5f), mEventSink(this)
19 {
20   // connect the timer event to the receiver
21   mEventSink.Connect(mTimer.Tick, &MyObject::OnTick);
22 
23   // start the timer (could be anywhere, anytime)
24   mStartTime = nglTime();
25   mTimer.Start();
26 }
27 
28 //**************************************
29 // timer event receiver
30 bool MyObject::OnTick(const nuiEvent& rEvent)
31 {
32   // a usefull shortcut using the empty constructor of nglTime 
33   double currentTime = nglTime();
34 
35   // my ending condition
36   if ((currentTime - mStartTime) > 5.f)
37     mTimer.Stop();
38 
39   // another way to use nglTime
40   nglTimeInfo info;
41   nglTime date;
42   date.GetLocalTime(info);
43 
44   NGL_OUT(_T("::OnTick currentTime %d/%d/%d %d:%d:%d\n"), 
45           info.Year + 1900, info.Month, info.Day, info.Hours, info.Minutes, info.Seconds);
46 
47   return true;
48 }


	

1.2) Inheriting from nglTimer

 1 class MyTimer : public nglTimer
 2 {
 3   [...]
 4   private:
 5 
 6   virtual void OnTick(nglTime Lap);
 7 };
 8 
 9 MyTimer::MyTimer(): nglTimer(0.5f)
10 {
11   Start(); // here or somewhere else ...
12 }
13 
14 // overloads the OnTick method
15 void MyTimer::OnTick(nglTime Lap)
16 {
17   // voila!
18 }

As you may have guessed, nuiTimer inherits from nglTimer using this method, and add the event interface to ease development and prevent having to do too much inheritance in the application code.





	

2. Threads

2.1) Inheriting from nglThread

 1 class MyClass: public nglThread
 2 {
 3   [...]
 4   virtual void OnStart();
 5   bool mDone;
 6 }
 7 
 8 MyClass::MyClass()
 9 : nglThread(_T("MyClass Thread")), mDone(false)
10 {
11 }
12 
13 // virtual callback 
14 void nglThread::OnStart()
15 {
16   while (!mDone)
17   {
18     // here is my threaded code
19 
20     if (Condition())
21       mDone = true;
22   }
23 
24  // the thread exits
25 }
26 
27 [...]
28 MyClass* myObj = new MyClass();
29 myObj->Start(); // launch ::OnStart callback
30 [...]


	

2.2) Threads synchronisation

 1 MyClass* myObj1 = new MyClass();
 2 MyClass* myObj2 = new MyClass();
 3 
 4 // launch the threaded processes
 5 myObj1->Start();
 6 myObj2->Start();
 7 // returns almost immediatly 
 8 
 9 // Join makes the process sleeps until the thread ends
10 myObj1->Join();
11 // same thing, for the other thread
12 myObj2->Join(); 
13 
14 // this way, we are now sure that all the threads have ended, and we can now safely delete everything.
15 delete myObj1;
16 delete myObj2;


	

2.3) Threads communication

We add a message queue to our class. External world can post notifications to this message queue.

 1 #define NOTIF_DONE _T("DONE")
 2 
 3 class MyClass: public nglThread
 4 {
 5   [...]
 6   // a method to post a message from outside
 7   void PostMessage(nuiNotification* pNotif);
 8 
 9 private:
10   // the local message queue
11   nuiMessageQueue mQueue;
12 };
13 
14 void MyClass::Post(nuiNotification* notif)
15 {
16   mQueue.Post(notif);
17 }
18 
19 // virtual callback
20 void MyClass:OnStart()
21 {
22   nuiNotification* pMessage;
23 
24   while (!mDone)
25   {
26     // wait for a message to come
27     pMessage = mQueue.Get();
28 
29     // if you need to, you can setup the message queue behavior:
30     // pMessage = mQueue.Get(100); // wait for 100ms only and then continue. If the queue was empty, the message is NULL!
31     // pMessage = mQueue.Get(0); // don't wait, check if a message is available and returns immediately. The message may be NULL!
32 
33     // process message
34     if (!pMessage->GetName().Compare(NOTIF_DONE))
35       mDone = true;
36 
37     delete pMessage;
38   }
39 }
40 
41 // from another part of the application
42 [...]
43 MyClass* myObj = new MyClass();
44 myObj->Start();
45 myObj->Post(new nuiNotification(NOTIF_DONE));
46 myObj->Join();
47 



	

2.4) Using a nglThreadDelegate

Sometimes you just don't want to create a whole class for your threaded process.
You are able to delegate the threaded process to an existing method, using the delegates system implemented in nui.

 1 [...]
 2 // declare the thread delegate
 3 nglThreadDelegate delegate(nuiMakeDelegate(this, &MyWidget::MyThreadDelegate));
 4 
 5 // and launch the thread process
 6 delegate.Start();
 7 [...]
 8 
 9 // here is the delegate method for the threaded process
10 void MyWidget:: MyThreadDelegate()
11 {
12   while (!mDone)
13   {
14     [...]
15   }
16 }



	

3. Critical Sections and Atomics

3.1) locking with critical sections

 1 class MyClass
 2 {
 3   [...]
 4   // the c.s. is a shared object for all threads
 5   nglCriticalSection myCS;
 6 }
 7 
 8 void MyClass::MyThreadedMethod()
 9 {
10   myCS.Lock(); // will block until the cs is released by the previous "thread-user" 
11 
12   // here is the code you want to protect from multiple parallel accesses
13   myAttribute = false;
14 
15   myCS.Unlock(); // release the cs 
16 }

You can also go for a convenient shortcut, using a guard:

1 void MyClass::MyThreadedMethod()
2 {
3   // handles the lock and release functions
4   nglCriticalSectionGuard guard(myCS);  // <=> nglGuard<nglCriticalSection> guard(myCS);
5 
6   // here is the code you want to protect from multiple parallel accesses
7   myAttribute = false;
8 }

3.2) locking with atomics

If you need to use atomics for an advanced locking system and if you know what you're doing, you can check the nglAtomic and nglLightLock classes.



	

Also available in: HTML TXT