7 Eylül 2017 Perşembe

std::istreambuf_iterator Sınıfı

Giriş
istream_iterator ile aynı şeyi yapar. Farklı olarak stream'den >> operatörü ile okumak yerine direkt stream'in belleğinden okur. Şu satırı dahil etmek gerekir.
#include <iterator>
Örnek
Dosyadaki herşeyi bir vector içine almak için şöyle yaparız.
std::ifstream ifs("X", std::ios::binary);
std::vector<char> v ((std::istreambuf_iterator<char>(ifs)),
                     std::istreambuf_iterator<char>());
Örnek
Dosyadaki herşeyi bir string içine almak için şöyle yaparız
ifstream ifs ("commented.cpp",ifstream::binary);

std::string str ((std::istreambuf_iterator<char>(ifs)),
                  std::istreambuf_iterator<char>());

6 Eylül 2017 Çarşamba

Gömülü Proje - Component

Giriş
Gömülü bir projede kullanılan yapı hakkında notlarım

Component Sınıfı
Component denince insanın aklına modül gelebiliyor. Component modülden daha üst seviyede. Belki birçok modülü de içerebilir.

initialize metodu
Initialize metodu ile tüm kaynaklar, bellek alınır.

activate metodu
activate veya start metodu ile sonsuz döngü, thread'ler başlatılır.

deactivate metodu
deactivate veya stop ile sonsuz döngü, thread' bitirilir.

getState ve setState metodu
Bileşenin durumu atanır. State değer olarak "Off", "Stanby", "Operational",  "Degraded" gibi değerler alabilir.

setMode metodu
Bileşenin modu atanır. Mode değer olarak "RX_Only", "TX_RX", "Radio_Silent" gibi değerler alabilir.

Diğer
Component kendisine gelen mesajları ilgili Manager sınıfına iletir. Eğer asenkron çalışması gerekiyorsa içindeki "iş kuyruğuna" ekler.

Application Sınıfı
Bu sınıfı aslında QApplicatin'dan esinlendi. Bu sınıf uygulamadaki tüm Component'leri içerir. 

activate metodu
Tüm componentlerin activate metodunu çağırır.

deactivate metodu
Tüm componentlerin deactivate metodunu çağırır.

getInstance metodu
Application nesnesine global olarak erişimi sağlar.

getConfiguration metodu
Configuration nesnesini döndürür.

readConfiguration metodu
Uygulamanın çalışması için gerek dosyaları okur ve Configuration nesnesinde saklar.

getXComponent metodu
X isimli ilgili componenti döner.

Mediator Sınıfı
Componentler arası haberleşme içindir.Çağrı silsilesi şöyledir. Çağrılar genellikle asenkron çağrılardır.
XManager --> Mediator--> Component --> YManager
XMediator Sınıfı
Component içindeki Manager sınıfları birbirleri ile mesajlaşmak isteyebilir. Bu durumda mediator örüntüsü kullanılır. ComponentMediator ve Component arasındaki ilişki şöyledir.
Component <---> XMediator
XMediator gelen mesajı Component'in getXManager metodunu kullanarak elde ettiği manager nesnelerine paslar.
XManager Sınıfı
Bu sınıfların kendi işleyiş mantıkları ve veri modelleri vardır. Her manager Mediator nesnesini bildiği için başka component'ler ve kardeş Manager nesneleri ile mesajlaşabilir. Çağrı silsilesi şöyledir. Çağrılar senkron çağrılardır.
XManager --> XMediator--> Component --> YManager
XContext Sınıfı
Bu sınıfın varlığı beni herzaman rahatsız etti. Amacı Component içindeki herkesin kullandığı ortak verileri saklamak. Global veriye kolay erişim sağlar.

Ancak prensip olarak her verinin bir sahibinin olması gerekir. Context mantığı ile verinin sahibini kaybediyoruz. Veriyi güncelleme mantığı da zamanla context içine taşınabiliyor. Dolayısıyla sanki sadece salt okunur veriyi saklamak için kullanmak daha mantıklı.

Örneğin component'in ismi, numarası vs. gibi şeyler tutulabilir.

Veri Modeli
Veri modeli ile ilgili iki seçenek var.

Global Veri Model
Global veri modelini en iyi anlatan temsili örnek sanırım Data Distribution System (DDS)
Global veri modeli güncellenince modeli dinleyen processor sınıfının oncreate (), onUpdate (), onDelete() gibi metodları tetiklenir.

Component ilklenirken DDS'in ilgili topiclerini dinleyecek Processor nesneleri yaratılır ve bağlanır
DDS indeksleme mekanizmasını sağladığı için sadece veri ile ilgilenilir. Her veriye birincil anahtar veya indeks ile erişlir. Topicler'in yani verinin ortak bir ata sınıftan kalıtması gerekir. DDS altyapısıını zorladığı kalıtım hiyerarşisi takip edilir. Ayrıca DDS verimodeline erişim için ortak metodlar sunar.


Lokal Veri Modeli
Bu yöntemde programcı kod yazar. Veri modelinde kullanılacak veri yapısı (list, map vs.) seçilir ve veri güncellenince event/signal yötemi ile modeli dinleyen sınıflar tetiklenir. Yani klasik observer örüntüsü kullanılır.

Veri modeli ihtiyaca göre

Clear (), DeleteByKey (...), DeleteByIndex (,,,.indexID), GetAll(), GetFirst (), GetNewest(), GetOldest(), GetSize (), IsEmpty (), AddOrUpdate (), AddProcessor() gibi bir sürü API sağlar.

Soyut bir veri modeli sınıfı tanımlayıp bundan kalıtmak ta mümkün.

Dağıtık Sistemler
Yukarıdaki Global Veri Modeli ve Lokal Veri Modelinin karışımı kullanılır.




5 Eylül 2017 Salı

Atomic İşlemler

Giriş
Atomic işlemler 3 başlık altında toplanabilir.
  1. sequentially-consistent ordering (memory_order_seq_cst), 
  2. relaxed ordering (memory_order_relaxed).
  3. acquire-release ordering (memory_order_consume, memory_order_acquire, memory_order_release, and memory_order_acq_rel), 
Sequentially Consistent Ordering
Anlaması en kolay model bu. Tüm thread'ler atomic bir işlemi tek bir thread yapmış gibi görür. Sıra bozulmaz.

Relaxed Ordering
Bu modelde, bir adamın elinde liste olsa ve listeden yeni bir elemen istesek ya yeni bir eleman ya da az evvel verdiği aynı elemanı verir. Açıklamayı OpenMP'den aldım ancak hemen hemen aynı şeyi açıklıyor.
...threads have access to a place to store and to retrieve variables, called the memory. In addition, each thread is allowed to have its own temporary view of the memory. ... The temporary view of memory allows the thread to cache variables and thereby to avoid going to memory for every reference to a variable.
Açıklaması şöyle
“Relaxed” atomic operations are not synchronization operations even though, like synchronization operations, they cannot contribute to data races.

Acquire Release Ordering
Örnek yaz

atomic_flag
std::atomic_flag yazısına taşıdım.


std::nextafter

Giriş
Şu satırı dahil ederiz.
#include <cmath>
Açıklaması şöyle
To increase/decrement a floating point value by the smallest possible amount, use nextafter towards +/- infinity().

If you just use next_after(x,std::numeric_limits::max()), the result with be wrong in case x is infinity.
Bu metod C99 ve C++11 ile eklendi. Eğer daha eski bir derleyici kullanıyorsak C++ için şöyle yaparız.
#include <limits>

typedef std::numeric_limits<double> lim_dbl;
double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;
Kullanım
Şöyle yaparız. İkinci parametre 1.0'dan sonraya veya önceye gitmek istediğimizi belirtir
std::nextafter(1., 0.); // 0.99999999999999989
std::nextafter(1., 2.); // 1.0000000000000002
Aynı şeyi C ile şöyle yaparız.
#include <math.h>

double closest_to_1 = nextafter(1.0, 0.0);
Denormal Sayı
Açıklaması şöyle
std::nextafter() is allowed to return a subnormal number
Şöyle yaparız.
double next = std::nextafter(0.0, 1.0);
Çıktı olarak şunu alırız.
next: 4.94066e-324
Yardımcı Metodlar
Generic yardmcı metodlarımız olsun istersek şöyle yaparız.
template<typename T>
T next_above(const T& v){
    return std::nextafter(1.0,std::numeric_limits<T>::infinity()) ;
}
template<typename T>
T next_below(const T& v){
    return std::nextafter(1.0,-std::numeric_limits<T>::infinity()) ;
}
Şöyle yaparız.
std::cout << next_below(1.0) << std::endl; 
std::cout << next_above(1.0) << std::endl;
Küçük bir not olarak şunu eklemek lazım. Positive infinity bir şekilde std::nextafter ile geriye alınabiliyor. Şöyle yaparız. İkinci örnekte görülebilir.
std::cout << std::nextafter(std::numeric_limits<double>::infinity(),
     std::numeric_limits<double>::infinity()) << std::endl; // gives inf
std::cout << std::nextafter(std::numeric_limits<double>::infinity(),
     std::numeric_limits<double>::max()) << std::endl; // gives 1.79769e+308

std::getenv

Giriş
Şu satırı dahil ederiz.
#include <cstdlib>
std::putenv diye bir metod yok.

Örnek
Şöyle yaparız.
std::cout << std::getenv("PATH") << std::endl;

4 Eylül 2017 Pazartesi

C++ ile Random Number Generator

C++11 ile eskiden sadece boost'un sağladığı birçok sınıf geliyor. Rastgele sayılar ile çalışırken çakışmalara hazırlıklı olmak gerekir.

Üreteç sınıfları - Generators

Generator sınıflarının amacı sayı üretmektir. İki çeşit üreteç var. Bunlar true random generator ve pseudo random number generator olarak sınıflandırılıyorlar.

true random number generator sınıflar donanım tabanlı ve yavaşlar. pseudo olanlar ise yazılım tabanlı ve hızlılar ancak daha kötü dağılım sağlıyorlar. Aşağıdaki şekillerde fark görülebilir.

True Random Number - Donanım Tabanlı


Pseudo Random Number - Yazılım Tabanlı

True Random Generator 
std::random_device yazısına taşıdım.

Pseudo Generator Sınıfları
Bu sınıfların isimleri _engine kelimesi ile biter.

İlklendirme
Pseudo random engine sınıflarını ilklendirmek için üç yöntem var. İlki true random generator kullanmak. Bu bence iyi bir fikir.
std::random_device rd;
std::mt19937 gen(rd());
İkincisi ise saati kullanmak. Ben bu fikri pek sevmiyorum. Bir başka örnek burada.
#include <random>
#include <chrono>

auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
C kodu kullanarak ilklendirmek için şöyle yaparız.
std::mt19937 generator(clock());
Üçüncüsü ise ilklendirmemek. Bu durumda default bir seed ile ilklenir. Bu zaten en kötü fikir.

1. default_random_engine
std::default_random_engine yazısına taşıdım.

2. mersenne_twister_engine 

1. mt19937
std::mt19937 yazısına taşıdım.

3. linear_congruential_engine
Bu sınıfın özelleşmiş hallerinden bir tanesi min_std_rand0. Bu sınıf şöyle tanımlı
linear_congruential_engine<uint_fast32_t, 16807, 0, 2147483647> minstd_rand0;
Sabitler sırasıyla a,c,m olarak anılıyor. Kullanılan formül şöyle
(a*x+c)%m

Sabitlerin base 8 olması gerektiği söyleniyor ancak ne kast edildiğini anlamadım

Dağılım Sınıfları - Distributions
Dağılım sınıflarının amacı üreteçlerin verdiği sayıları belli bir örüntüye göre (Uniform, Normal, Binomial) dağıtmaktır. Her dağılım sınıfı constructor metodu bir engine ile beraber çalışır.

  • Uniform Distribution - Tek Düze Dağılım demektir
  • Normal Distribution - Çan eğrisi dağılım demektir. Gaussian olarak ta bilinir. 
  • Bernoulli - Binomial Distribution - Binom dağılım demektir
  • Rate based Distribution 
  • Piecewise Distribution 
  • Canonical Number
gibi sınıflar var.

Nasıl Kullanırız


Dağılım sınıflarının constructor metodlarına aralık girilir. Daha sonra distribution sınıflarının () metodu verilen üreteci kullanarak sayı döndürür.

normal_distribution
normal_distribution Sınıfı yazısına taşıdım

uniform_int_distribution
uniform_int_distribution Sınıfı sınıfı yazısına taşıdım.

uniform_real_distribution
uniform_real_distribution Sınıfı yazısına taşıdım.

discrete_disctribution
discrete_disctribution Sınıfı yazısına taşıdım.

Engine Adapters
  • Discard Block Engine 
  • Independent Bits Engine 
  • Shuffle Order Engine
gibi sınıflar var.

std::add_pointer

Giriş
C++11 ile geliyor.

Örnek
void * tanımlamak için şöyle yaparız.
auto ptr = std::add_pointer_t<void>{};