Basit Timer Yapıları
Geleneksel Yaklaşım: alarm()
alarm()
Timer kullanımının en basit yolu, prototipi aşağıda verilmiş olan alarm
fonksiyonunu kullanmaktır:
Bu yöntemle ancak saniye çözünürlüğünde zaman belirtmek mümkündür. Zaman sona erdiğinde işletim sistemi uygulamaya SIGALRM
sinyalini gönderir. Zamanlayıcının dolduğunu uygulamada işleyebilmek için bu sinyali işleyecek callback fonksiyonu da tanımlanmış olmalıdır.
Aşağıda 1 saniyelik zamanlayıcı kurulması ve sinyal işleyici fonksiyonun tanımlanması örneklenmiştir:
Bu şekilde kurulmuş olan bir timer her 1 saniyede uygulamaya sinyal gönderecektir. Eğer belirli bir eylem olduğunda timer aralığını örnek olarak 5 saniyeye çıkarmak isterseniz, alarm(5)
şeklinde fonksiyonu yeniden kullanmanız yeterli olacaktır.
Timer'ı durdurmak isterseniz, alarm(0)
şeklinde 0 parametresi ile kullanmanız yeterli olacaktır. Bu şekilde durdurulmuş bir timer, 0'dan büyük bir değer verilerek fonksiyon tekrar çağrılırsa yeniden başlatılacaktır.
Zaman dolduğunda kullandığınız timer periyodik olarak tekrar baştan başlamayacaktır. Örnek olarak her 1 saniyede callback fonksiyonunuzun çağrılmasını istiyorsanız, timer dolduğunda tekrar alarm(1)
şeklinde mekanizmayı başlatmanız gerekmektedir.
Alarm fonksiyonu üzerinden örneklediğimiz bu yapı ancak çok basit senaryolarda tercih edilmelidir (bu yüzden sinyal yakalama kısmını da Sinyaller bölümünde işlediğimiz sigaction()
yöntemiyle değil signal()
fonksiyonuyla yaptık). Kullanım kolaylığına rağmen bu yöntemin başlıca dezavantajları:
aynı anda sadece tek bir timer olması
periyodik timer desteği olmaması
timer çözünürlüğünün sadece saniyenin katları cinsinden verilebilmesi
timer için kalan sürenin ne kadar olduğunu öğrenmenin bir yolu olmaması
event loop mekanizması içerisinden kullanımına yönelik bir destek sunmaması
olarak sıralanabilir.
Şimdi tekrar yukarıda verdiğimiz örneğe geri dönelim. Uygulamayı alarm.c
adıyla kaydedip, derleyip çalıştırdığımızda 1 saniye geçince timer_callback fonksiyonu çağrılacak, sleep(3)
satırı nedeniyle kalan 2 saniye boyunca bekleyecek ve düzgün bir şekilde sonlanacak mıdır?
Süreleri ölçebilmek için uygulamayı time
komutunu vererek çalıştırdık. Fakat görüleceği üzere toplam çalışma süresi 3 saniye değil, toplamda 1 saniye şeklinde gerçekleşti. Neden?
Daha önceki Sistem Çağrıları ve Sinyaller konularında değindiğimiz maddeleri hatırlayınız. sleep(3)
fonksiyonunun yol açtığı sistem çağrısı çalışıyorken 1. saniye dolduğunda alarm(1)
'den kaynaklanan SIGALRM
sinyali geldiğinde, sleep(3)
için başlatılan sistem çağrısı kesintiye uğradı.
sleep()
fonksiyonu sistem çağrısı tarafından kesintiye uğradığında saniye cinsinden kalan zamanı geri döndürür. Zaman tamamen bitip normal şekilde geri döndüğünde ise 0 döndürür. Bu özelliği dikkate alarak, global errno
değişkeni ile de INTERRUPT
durumu olup olmadığını test ederek uygulamamızı aşağıdaki gibi daha güvenli hale getirebiliriz. Ek olarak alarm sinyalini işlediğimiz timer_callback fonksiyonunda ilgili alarmı tekrar kurup periyodik çalışmasını sağladığımıza ve while döngüsüne girmeden önce yarım saniyelik ek bir bekleme koyduğumuza dikkat ediniz:
Şimdi uygulama çıktısına tekrar göz atalım:
Bu defa uygulamamız yaklaşık 4 saniye kadar çalışıp sonlandı. Oysa beklentimiz 3.5 saniye kadar sürmesi idi. Uygulama çıktısını daha dikkatli inceleyip nedenini yorumlamaya çalışınız.
Interval Timer Kullanımı
Interval timer mekanizması ilk olarak 4.2BSD versiyonunda görülmüş sonradan POSIX tarafından standardize edilmiştir.
Geleneksel alarm()
tabanlı timer yöntemine oranla temel avantajları aşağıdaki şekilde sıralanabilir:
mikrosaniye seviyesinde çözünürlük sağlar
zaman ölçümünü 3 farklı mod üzerinden daha detaylı kontrol etme imkanı verir
bir defa ayarlayıp, periyodik olarak çalışmasını sağlamak mümkündür
herhangi bir anda ne kadar zaman kaldığı sorgulanabilir
Interval timer işlemleri için kullanılan fonksiyon prototipleri aşağıdaki gibidir:
Interval timer kurmak istendiğinde setitimer
fonksiyonunun 2. parametresine, istemiş olduğumuz timer ile ilgili zaman bilgilerini, ilk çalıştığında istenen süre (veri yapısının it_value
elemanı), sonraki çalışmalarında istenen süre (veri yapısının it_interval
elemanı) biçiminde vermemiz gereklidir.
Örnek olarak, önce 1 saniye ardından 300 milisaniyede bir uygulamamızı haberdar edecek bir interval timer aşağıdaki şekilde kurulabilir:
Fonksiyonun 3. parametresine verilen itimerval
türündeki değişken adresine, yeni değerler ayarlanmadan önce aktif durumda olan bir interval timer var ise onun değerleri aktarılır.
Interval timer mekanizmasıyla 3 farklı tipte timer kurulması mümkündür. Kullanılacak timer tipi setitimer()
fonksiyonunun ilk parametresinde belirtilir.
Timer Tipi
Sinyal
Açıklama
ITIMER_REAL
SIGALRM
Uygulamanın harcadığı zamandan bağımsız, toplam geçen zaman üzerinden hesaplanır
ITIMER_VIRTUAL
SIGVTALRM
Uygulamanın sadece kullanıcı kipinde çalıştığı zaman üzerinden hesaplanır
ITIMER_PROF
SIGPROF
Uygulamanın hem kullanıcı kipinde harcadığı zaman, hem de yapmış olduğu sistem çağrıları içerisinde harcamış olduğu zamanın toplamı üzerinden hesaplanır. Pratikte uygulama içerisinde ITIMER_VIRTUAL ile birlike ayrı ayrı kurulup, uygulamanın kullanıcı kipi ve çekirdek kipinde ayrı ayrı ne kadar zaman harcadığını hesaplamakta kullanılır.
Yukarıdaki tabloyu incelediğimizde, ITIMER_REAL tipinde bir interval timer kurduğumuzda, tıpkı alarm()
fonksiyonu ile kurmuş olduğumuz timer mekanizmasında olduğu gibi, SIGALRM sinyali ile uygulamamızı uyandıracağını görebiliriz. Dolayısıyla bu şekilde bir interval timer ile alarm()
fonksiyonunun aynı uygulamada kullanımı, her ne kadar sinyalin işlendiği fonksiyonda getitimer()
fonksiyonuyla kalan zaman üzerinde ikinci bir kontrol yapılmak suretiyle çözüm üretmek mümkün olsa da kafa karıştıracak ve yönetimi güçleştirecektir. Bu nedenle aynı anda kullanımı önerilmez.
Önceki örneğimizi interval timer kullanacak şekilde aşağıdaki gibi değiştirip çalıştıralım:
Yukarıdaki kodda öncelikle 1 saniye, sonra da 300 milisaniyede bir interval timer kurulmuş ve tıpkı ilk örneğimizdeki gibi, toplam çalışma süresi 3 saniye olacak şekilde sleep()
fonksiyonunun sinyal tarafından kesintiye uğraması durumu ele alınmış. Örnek kodu interval.c
isminde kaydedip derleyelim ve çalıştıralım:
Uygulamamız timer ilk çalıştıktan sonra çıktıdan da anlaşılacağı üzere tam da beklediğimiz gibi 300 milisaniyede bir callback fonksiyonumuzu çağırdı. Ancak biraz daha beklenildiğinde uygulamanın sonlanmadığı ve 300 milisaniyede bir callback fonksiyonunu çalıştırmaya devam ettiği görülecektir. Interval değerini 600 milisaniye yaptığınızda ise uygulamanın sonlandığını görebilirsiniz.
sleep()
fonksiyonu etrafında düşünerek bu davranışın nedenlerini bulmaya çalışınız.
Last updated
Was this helpful?