28 Ağustos 2016 Pazar

asio timer

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.

Hiç yorum yok:

Yorum Gönder