Basics overview part II: Timers, Threads and Critical Sections¶
- Basics overview part II: Timers, Threads and Critical Sections
- 1. Timers
- 1.1) using a nuiTimer instance
- 1.2) Inheriting from nglTimer
- 2. Threads
- 2.1) Inheriting from nglThread
- 2.2) Threads synchronisation
- 2.3) Threads communication
- 2.4) Using a nglThreadDelegate
- 3. Critical Sections and Atomics
- 3.1) locking with critical sections
- 3.2) locking with atomics
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.