Timer sınıfları
4 tane timer sınıfı var. Her timer sınıfı farklı bir clock
kullanır. Dolayısıyla hassasiyetleri farklıdır.
1. deadline_timer :
deadline_timer Sınıfı yazısına taşıdım.
2. system_timer : Chrono sistem saatini kullanır.
Örnek
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(5));
3. steady_timer :
steady_timer Sınıfı yazısına taşıdım.
4. high_resolution_timer :
high_resolution_timer Sınıfı yazısına taşıdım.
Metodlar
Constructor
Timer sadece io_service ile kurulursa, expire etme zamanı
atanmamıştır. expires_at () veya expires_from_now() absolute veya relative time atamak gerekir.
boost::asio::steady_timer timer(io_service);
Bir başka
örnek
boost::asio::deadline_timer timer(io_service);
Constructor + expiration time
Absolute veya relative time alan bir constructor daha var. expires_at() veya expires_from_now() metodunu çağırmaya gerek kalmaz.Şöyle
yaparız.
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(3));
async_wait metodu
Metodun imzası şöyle. void dışında başka bir şey de
dönebiliyor.
template<typename WaitHandler>
void-or-deduced async_wait(WaitHandler handler);
Açıklaması
şöyle
By default, initiating functions return void. This is always the case when the handler is a function pointer, C++11 lambda, or a function object produced by boost::bind or std::bind.
For other types, the return type may be customised via [...] a specialisation of the async_result template, which is used both to determine the return type and to extract the return value from the handler.
Asenkron olarak verilen handler'ı
çağırır. Bu metodu çağırmadan önce timer'ın expires_from_now() veya expires_at() ile ilklendirilmesi gerekir.
void handle_timer(const boost::system::error_code& error) {...}
void schedule_work()
{
// Schedule more work.
timer.expires_from_now(boost::chrono::milliseconds(10));
timer.async_wait(&handle_timer);
}
Eğer istersek handler olarak lambda kullanabiliriz. Şöyle
yaparız.
timer.async_wait([](const boost::system::error_code& error) {
...
});
cancel metodu
Şöyle
çağrılır.
timer.cancel();
1. Timer cancel olsa bile daha önceden kuyruğa yerleştirilmiş bir event
gelebilir.
2. Eğer io_service henüz çalışmaya başlamamışsa ve biz timer nesnesini cancel() edersek, timer nesnesine atadığımız handler metodu çağrılır. Metod boost::asio::error::operation_aborted değeri ile çağrıldığı için normal bir timeout olayından ayırt
edebiliriz.
expires_at metodu - getter
Şöyle
yaparız.
if(timer.expires_at() <= boost::asio::deadline_timer::traits_type::now()) {...}
expires_at metodu - setter
Şöyle
yaparız.
// set timer to infinity, so that it won't expire
// until a proper deadline is set
timer.expires_at(boost::posix_time::pos_infin);
expires_from_now metodu
Kullanılan saat türüne göre duration kullanılır. Chrono saatleri için boost veya std chrono duration sınıfları
kullanılır.
timer.expires_from_now(boost::chrono::milliseconds(10));
Şöyle
yaparız.
timer.expires_from_now(boost::posix_time::seconds(20));
Eğer expire etmemiş bir timer, tekrar kurulursa timer nesnesine atadığımız handler metodu çağrılır. Açıklaması şöyle
This function sets the expiry time. Any pending asynchronous wait operations will be cancelled. The handler for each cancelled operation will be invoked with the boost::asio::error::operation_aborted error code.
Şöyle
görebiliriz.
boost::asio::io_service io;
boost::asio::deadline_timer timer(io, boost::posix_time::seconds(3));
timer.async_wait(...);
timer.expires_from_now(boost::posix_time::seconds(20)); //Tetikler
timer.async_wait(...);
Handler boost::asio::error::operation_aborted değeri ile çağrıldığı için normal bir timeout olayından ayırt
edebiliriz. Şöyle
yaparız.
void handler1(const boost::system::error_code &ec)
{
if (ec == boost::asio::error::operation_aborted)
{
std::cout << "cancelled" << std::endl;
}
else
{
std::cout << "expired." << std::endl;
}
}
wait metodu
Sleep ile aynı işlevi
görür. Şöyle
yaparız.
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
Boost örneklerinde şöyle bir kod
var.
#include <boost/asio/steady_timer.hpp>
boost::asio::io_service io_service;
boost::asio::steady_timer timer(io_service);
int main()
{
for (;;)
{
timer.expires_from_now(boost::chrono::milliseconds(10));
work();
timer.wait();
}
}
Düz Sleep çağrısından farklı olarak work() için harcanan süre otomatik olarak düşülür.
Bu durumda sleep'ten farklı olarak kalan süre kadar bekleriz. Böylece ne kadar sleep etmemiz gerektiğini hesaplamak zorunda kalmayız.
Timer Kuyruğu
asio timer kuyruğu aynı ACE kütüphanesinde olduğu gibi bir heap kullanıyor. Kaynak koddan heap kullandığı
görülebilir. ACE kütüphanesi timer kuyruğu için iki farklı seçenek kullanma imkanı
veriyor. Bunlar ACE_Timer_Heap (default) ve ACE_Timer_Wheel sınıfları. asio böyle bir imkan tanımıyor. Heap kullanınca average ve worst case maliyet O(lgn)
Niçin Windows'taki işletim sistemi tarafından sağlanan timer kuyrukları kullanılmıyor bilmiyorum. Windows bu imkanı
sunuyor.
CreateTimerQueue - kuyruk yarat
CreateTimerQueueTimer - kuyruğa timer ekle
DeleteTimerQueueTimer - kuyruktan timer sil
Linux'ta ise işletim sistemi tarafından sağlanan timerfd_create metodu kullanılıyor
deniyor.
Timer ve IO Service
Windows'ta timer için ikinci bir thread
açılıyor.
void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue)
{
mutex::scoped_lock lock(dispatch_mutex_);
// ...
if (!timer_thread_.get())
{
timer_thread_function thread_function = { this };
timer_thread_.reset(new thread(thread_function, 65536));
}
}
Linux'ta ise açılmıyor.