13 Ocak 2017 Cuma

Gömülü Proje - Fixed Rate Timer

Giriş
Amacımız belli bir süreden önce (örneğin 30 saniye) yenilenmesi gereken nesneleri yönetmek. Eğer belirtilen süre içinde yenilenmezse o nesne için kurulan TimerHandler nesne için belirtilen TimerKey ile çağrılır. Eğer nesne yenilenirse timer bir kere daha 30 saniye sonrasına kurulur.

FixedRateTimerManager nesnesi Component veya Manager içinde yaşar. Bu nesneler ana thread tarafından çalıştırılır. Böylece timer nesnesi de sürülmüş olur.
Main Thread-->Component -->Manager -->FixedRateTimerManager

Tasarım
TimerKey, ITimerHandler, FixedRateTimer, FixedRateTimerManager sınıflarından oluşur.

TimerKey
3 tane unsigned int alan bir yapı olsun. Bu yapı tasarımdaki önemli noktalardan birisi.

Bazı tasarımlarda, timer key alanı olmadan çalışır. Örneğin amaç 30 saniyede bir liste üzerinde yürümektir. Bu amaç için key alanı saklamak gerekmez.

Bazı tasarımlarda, her timer nesnesinin bir ID alanı vardır. Timer tetiklenince ID bilgisini de verir. Kod yazan kişi ID üzerinden haricen yönettiği state bilgisine erişir ve bir işlem yapar. Ancak bu da zor bir tasarım çünkü timer ile haricen tutulan "map" veri yapısını birlikte yönetmek gerekir.

Benim seçtiğim yöntemde timer tetiklenirken state bilgisini de sağlıyor. Böylece her şey daha kolay bir hale geliyor. State her zaman int tipi olduğu için sorun olmadı.

Bir diğer yöntem ise state bilgisini handler içinde saklamak. Handler yaşam döngüsü heap üzerinde olabilir. Timer bitince handler da silinebilir. Ancak gömülü ortamda malloc/new yapmamak için bu yöntemi seçmedim.

ITimerHandler
ITimerHandler isimli bir arayüzümüz olsun. Bu arayüzün TimerKey nesnesi alan OnTimeOut metodu olsun.
void OnTimeOut (TimerKey& key);

FixedRateTimer
Intrusive bir yapı. pNextTimer, pPrevTimer,isPeriodic,ExpirationTime,isActive alanları olsun.

FixedRateTimerManager
FixedRateTimerManager isimli bir sınıfımız olsun. Bu sınıf tüm FixedRateTimer nesnelerini iki veri yapısı kullanarak yönetsin.

İlk yapı bir "double linked list" olsun. Bu yapı nesneleri absolute timeout zamanına göre sıralı saklasın. Yani bitme zamanı en yakın olan nesne en başta,  bitme zamanı en uzak olan nesne ise en sonda olsun. Absolute time kullanabilmek için sistemde sürekli artan bir monotonic zaman kaynağı olması yeterli.

İkinci yapı ise bir "hashmap" olsun. Belirtilen TimerKey değerine sahip TimerHandler nesnesi silinebilsin, tekrar kurulabilsin.

FixedRateTimerManager belirtilen bir TimerKey nesnesi için bir TimerHandler eklerken her iki yapıyı da kullansın.

FixedRateTimerManager yönettiği belli bir TimerKey için yeniden kurma imkanı sağlasın. Yeniden kurulan timer listenin en sonuna taşınır. Aslında burası en kritik nokta. Tüm nesnelerin aynı timeout süresini kullandığını bildiğim için liste içinde dolaşarak timer nesnesini doğru yere yerleştirmekle uğraşmıyorum. Yani liste kendiliğinden sıralı oluyor.
Elimdeki liste şöyle olsun
A (30) , B (60) , C (60)
Şu anki saat ise 30 olsun. A nesnesi tekrar kurulunca liste şöyle olur.
B (60), C (60), A (90)

FixedRateTimerManager (TimeSpan& rate);
Kullanılacak sabit süre belirtilir.

void RunTimers () metodu çağrılınca liste dolaşılır.  Biten FixedRateTimer nesnesi tetiklenir. Eğer nesne periyodik ise bir sonraki tetiklenme zamanı aranir ve listenin en sonuna taşınır. Eğer nesne "single shot" ise listeden silinir.

bool StopTimer (TimerKey & key);
Belirtilen anahtar değerine sahip timer listeden silinir.

bool StartOrRescheduleTimer (TimerKey & key, ITimerHandler* pHandler);
Eğer belirtilen timer yoksa yeni bir timer başlatılır. Varsa 30 saniye sonrası için tekrar kurulur.


Hiç yorum yok:

Yorum Gönder