29 Aralık 2015 Salı

IPC (Inter Process Communication)

Not: Pipe ile ilgili olarak Non-Blocking I/O başlıklı yazıya göz atabilirsiniz

ipcs Komutu
ipcs komutu ile IPC için kullanılan yapılar görülebilir.

Unnamed Pipe
Unnamed Pipe uygulama içi haberleşmek veya fork() ile beraber kullanılır. Unnamed pipe ile ilgili olarak gördüğüm en güzel yazı Beej's Guide to Unix IPC başlıklı yazı.

pipe açmak
Pipe ile açılan iki tane file descriptor vardır. fd [0] okuma için, fd [1] ise yazma için kullanılır.
int pipefd[2];
pipe(pipefd);
yazma ucu
fd[0] okuma ucu, fd[1] yazma ucudur. fork() ile kullanıyorsak geleneksel olarak okuyan taraf yazma ucunu kapatır.
// Fork
switch(fork())
{
  case 0:
    // Close unused write side
    close(pipefd[1]);
    while(1)
    {
      char c;
      // Read only one byte
      int ret = read(pipefd[0], &c, 1);
      printf("Woke up\n", ret);
      fflush(stdout);
    }
    default:
      // Close unused read side
      close(pipefd[0]);
      size_t len = 0;;
      char *str = NULL;
      while(1)
      {
        int nbread;
        char buf[65535];
        while (getline(&str, &len, stdin)) {
          if (sscanf(str, "%i", &nbread)) break;
        };
        // Write number byte asked
        int ret = write(pipefd[1], buf, nbread);
        printf("Written %d bytes\n", ret);
        fflush(stdout);
       }
    }

pipe büyüklüğünü ayarlamak
Linux'ta Pipe için çekirdekte ayrılmış olan alanın boyunu ayarlamak için fcntl() ve F_SETPIPE_SZ parametreleri beraber kullanılabilir.
int pipe_sz = fcntl(pipe_des[1], F_SETPIPE_SZ, sizeof(size_t));
En az system page size, en çok /proc/sys/fs/pipe-max-size değer arasında bir sayı verilebilir.

Yazma Ucunu NonBlocking Yapmak
fd [1] flag'i değiştirilerek yapılır.
int flags = fcntl(pipefd[1], F_GETFL, 0); // set write operation non-blocking
assert(flags != -1);
fcntl(pipe_des[1], F_SETFL, flags | O_NONBLOCK);

read işlemi
POSIX standardı pipe'ların read() işlemi için aşağıdaki bilgileri tanımlamış.
  • Eğer child pipe'ı kapatırsa, parent read() işlemine teşebbüs edince işlem 0 değerini döner.
  • Eğer child pipe'ı kapatmamışsa ve pipe için O_NONBLOCK bayrağı atanmışsa parent read() işlemine teşebbüs edince okunacak veri yoksa işlem -1 değerini döner ve errno'ya EAGAIN değeri atanır.
  • Eğer child pipe'ı kapatmamışsa ve pipe için O_NONBLOCK bayrağı atanmamışsa parent read() işlemine teşebbüs edince okunacak veri yoksa işlem okunacak veri gelinceye kadar bloke olur.
dup
dup en küçük müsait file descriptor değerini kullanarak, kopyalama yapar.
pipe'ın okuma ucunu stdin'e yönlendirmek için aşağıdaki kod kullanılır.
// Redirect pipes[0] to stdin
close(pipes[1]);
close(0);
dup(pipes[0]);
close(pipes[0]);

dup2
dup2 yazısına taşıdım.

Named Pipe
İki uygulama arasında iletişim sağlamak için kullanılabilecek yöntemlerden birisi olarak named pipe gösteriliyor.

mkfifo komutuyla ismi olan bir pipe yaratılır
int myPipe = mkfifo("pipe", S_IRUSR | S_IWUSR);
Daha sonra yaratılan pipe open() ile açılır.
char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666); //Make the fifo
int fd = open(myfifo, O_WRONLY);
Named pipe bash tarafından subshell çalıştırmak için de sıkça kullanılır. Örnek'te dikkat edilirse "|" işareti kullanılmıyor.
cat <(ls -l)
ls komutunun çıktısı bash tarafından bir named pipe'a dolduruluyor. Böylece cat'in okuyabileceği bir dosya oluşmuş oluyor.

Yazmak için kullanılan open komutu normalde okuyan taraf olmadıkça bloke olur.

"The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.

A process can open a FIFO in nonblocking mode. In this case, opening for read only will succeed even if no-one has opened on the write side yet, opening for write only will fail with ENXIO (no such device or address) unless the other end has already been opened."


Socket Pair
socketpair ile dikkat edilmesi gereken en önemli nokta aşağıdaki cümle

Pipes and socketpairs are limited to communication between processes with a common ancestor.
Yani bu yöntem de fork() yöntemiyle ortak bir atadan gelen ik uygulama için kullanılabilir. socketpair() metodu Windows üzerinde mevcut değildir. socketpair ile stream veya datagram socketler açılabilir.
Stream socket açma örneği aşağıda bulunabilir.


socketpair ile farklı uygulamalar arasında ancillary (yardımcı) mesaj geçebilmek te mümkün. Konuyla ilgili olan bu yazıya göz atabilirsiniz.

Unix domain socketi ile ilgili olarak QLocalSocket'e göz atmak ta faydalı olabilir.Aşağıda QLocalSocket sınıfının hiyerarşisini görmek mümkün.


Shared Memory
Shared Memory kullanmak için shm_open() ve mmap() sistem çağrılarını kullanmak lazım. shm_open() ile ismi olan bir shared memory parçası yaratılıyor ve bu parça bir file descriptor olarak döndürülüyor. Yaratılan shared memory alanını /dev/shm dizini altında görmek mümkün. shm_open() örnekleri için Shared Memory başlıklı yazıya bakabilirsiniz.

Burada , umask ayarlarının, yaratılan shared memory dosyasının izinlerini etkileyebileceği de belirtilmiş.

Yaratılan shared memory parçasını kapatmak için shm_unlink kullanılıyor.

Not : shm_open() yerine shm_get() metodu da kullanılabilir ancak shm_get ile isim yerine bir anahtar değer kullanmak gerekiyor.shm_open() ve shm_get metodlarının karşılaştırmasını shmget vs. shm_open başlıklı yazıda görebilirsiniz.

Not :  Linux ve Windows arasında shared memory'nin ne zaman yok edileceğine dair farklılıklar var. Konuyla ilgili olarak QSharedMemory sınıfına bakabilirsiniz. En temel fark, Windows'ta shared memory yaratan program çökerse işletim sistemi tarafından silinir. ancak Unix'te shared memory shm_unlink çağırılmadığı müddetçe var olmaya devam ediyor.



Burada dikkat edilmesi gereken nokta mmap() metodu aynen malloc() gibi sanal bir adres döndürür.
boost kullanan örnekleri boost interprocess kütüphanesi başlığı altında bulabilirsiniz.

shmget yöntemi
shmget ile Shared Memory yazısına taşıdım.

Büyük Dosyaları Okumak İçin
Memory Mapped File yöntemiyle büyük dosyalar daha kolay yüklenir.Bu yöntem ile ilgili olarak Memory Mapped File başlıklı yazıya göz atabilirsiniz.
Memory Mapped I/O (Hafızaya eşlenmiş giriş/çıkış)
Yöntem itibariyle Memory Mapped File ile aynı şey. Bu kez dosya yerine bir cihaz açılıyor ve cihazın file descriptor numarası kullanılıyor.Konuyla ilgili olarak Memory Mapped File başlıklı yazıya göz atabilirsiniz.


Hangi amaçla kullanılmış olursa olsun, yaratılmış olan Shared Memory ya da bir file descriptor, mmap() sistem çağrısı kullanılarak uygulamanın adres alanına (address space) dahil edilir. Aşağıdaki şekil nasıl çalıştığını özetliyor.

mmap Shared Memory



Posix Message Queue
Message queue kullanmak için iki farklı API seti var, ve anladığım kadarıyla her ikisi de standardın bir parçası. İlk API seti msgXXX ile başlıyor, diğeri ise mq_XXX ile başlıyor.

Posix Message Queue işletim sistemi tekrar başlatılırsa yok olur.
  
Posix ile message queue kullanabilmek mümkün. mq_overview başlıklı yazıda güzel bir özet var. Burada dikkat edilmesi gereken nokta, mq_open() sistem çağrısı ile yaratılan kuyruk int yerine mqd_t verisi dönmektedir.Dolayısıyla bu yapı normal file descriptorlardan farklı olup select/poll gibi non-blocking çalışmayı sağlayan sistem çağrıları ile beraber kullanılamazlar. Her ne kadar Linux üzerinden bu çağrılar çalışsa da kod portable olmaz ! Burada libev ile kullanıma bir örnek var.

Bir diğer bilgi ise Posix Message Queue kuyruğunun azami uzunluğunu /proc/sys/fs/mqueue/msg_max altında görebilmek mümkün. Ancak uzunluğu nasıl değiştirebiliriz bilmiyorum.

Kuyruğu Yaratmak ve Yazma/Okumaya Açmak İçin


msgget
Yeni bir kuyruk açmak için örnek:
#define PERMS (S_IRUSR | S_IWUSR) 
int msqid = msgget(IPC_PRIVATE, PERMS);
mq_getattr
Bu metod ile kuyruğun özelliklerini almak mümkün.Örneğin kuyruğun non_blocking olup olmadığını anlamak için aşağıdaki gibi yapılabilir.
mq_attr mystruct;
mqd_t mqdes;//opened fd
mq_getattr (mqdes,&mystruct);
if (mystruct.mq_flags & O_NONBLOCK) //nonblocking
Kuyruktaki elemanların ne kadar büyük olduğunu anlamak için aşağıdaki gibi yapılabilir.
mq_getattr(mq , &attr);
printf("mq maximum msgsize = %d\n" , (int) attr.mq_msgsize);

mq_open
mq_open kullanabilmek için
#include <mqueue.h> yapıp librt ile -lrt şeklinde link etmek lazım.

Default değerler ile açmak için aşağıdaki kod lazım.
mqd_t queue = mq_open("unique_name", O_RDWR|O_CREAT);
Exclusive açmak için. Bu ne için lazım bilmiyorum.
mqd_t queue = mq_open("unique_name", O_RDWR | O_CREAT | O_EXCL);

Eğer kullanıcılara bazı haklar tanıyarak açmak istiyorsak aşağıdaki kod lazım.

mqd_t qd = mq_open("/tempqueue", O_RDONLY | O_CREAT, 0666, NULL);
O_RDWR : Open the queue to both send and receive messages.

Eğer kuyruğun uzunluğunu ve mesaj  büyüklüğünü kendimiz değer atamak istiyorsak aşağıdaki kod lazım.
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 1000;
attr.mq_msgsize = sizeof(int_32);

mqd_t queue = mq_open("unique_name", O_RDWR|O_CREAT, 0600, attr);
mq_attr yapısı aşağıdaki gibi.

Tanımlanan maxmsg ile kuyruğun uzunluğu atanabilir. Ancak bloke olmadan kaç tane eleman yazılabileceği /proc/sys/fs/mqueue/msg_max dosyasında tanımlı.

Kuyruğa Yazmak İçin
msgsnd
Örnek:
int len = 250;
mymsg_t* mbuf = malloc(len);
mbuf = //populate
msgsnd(msqid, mbuf, len, 0);

mq_send 
Örnek:
struct item  {
    int maxvalue;
    int minvalue;
    char queuename [50];
};
item.maxvalue = 1;
item.minvalue = 100;
stcpy (item.queuename,"test");
mq_send(mq , (char *) &item , sizeof(item) , 0);
Kuyruktan Okumak İçin
msgrcv
Bu çağrının imzası şöyle:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
Çağrıya geçilen 3. parametre yani msgtyp 0 ise kuyruktaki ilk eleman okunur.

Örnek:
mymsg_t mymsg; //buffer to hold message
int size = msgrcv(msqid, &mymsg, len, 0, 0);

mq_receive
Örnek:
mqd_t qd; //mq_open() ile açılır
char buf[400];
mq_receive(qd, buf, 400, NULL);//Mesajı okumak için buf yeterince büyük olmalı
Kuruğa Mesaj Gelince Signal İle Haberdar Olmak İçin
Örnek:
void handler()
{
}
signal(SIGUSR1, handler);
sigevent.sigev_signo = SIGUSR1;;
mq_notify (msgq_id, &sigevent);

Kuyruğu Kapatmak İçin
Örnek:
mqd_t qd = mq_open("/tempqueue", O_RDONLY | O_CREAT, 0666, NULL);

Kuyruğu Silmek İçin
mq_close(qd); //Kuyruğa erişimi kapat
mq_unlink("/tempqueue"); //Kuyruğu sil

boost
Send complex data structure via boost message queue sorusunda boost ile message queue kullanılması örneği var.
Message queue açmak için

#include <boost/interprocess/ipc/message_queue.hpp>
message_queue mq
            (
             open_or_create,
             "mq",
             100,
             MAX_SIZE
            );
okumak içinse

message_queue mq
            (
             open_only,
             "mq"
            );
yapmak lazım.

24 Aralık 2015 Perşembe

makefile ve değişken

Varsayılan (Default) Değişkenler
Make bazı değişkenleri kendisi tanımlar. Çok kullanılan bazı değişkenler şu işe yarar.

CPPFLAGS : C Preprocessor'ına geçilecek parametreleri belirtir.
CFLAGS : C derleyicisine geçilecek parametreleri belirtir.
CXXFLAGS : C++ derleyicisine geçilecek parametreleri belirtir.
LDFLAGS : Linker'a geçilecek parametreleri belirtir.
LDLIBS : Linklenecek kütüphaneler belirtir.

Ayrıca
CC sistemdeki C derleyicisini belirtir.
MAKE sistemdeki make uygulamasını belirtir.

CXX
Şöyle kullanırız.
$> CXX='g++ -m32' make
CC
Şöyle kullanırız.
make CC='gcc -m32' CXX='g++ -m32'

Değişkenin Değerine Erişme
Değişkenin değerine $(var_name) şeklinde erişilir.

Ortam Değişkeni
Ortam değişkeninin değerine de yine $ işareti ile erişilir. TEST isimli bir ortam değişkenini If testine sokmak için şöyle yaparız. ifreq'ten önce tab olmamalıdır.
test_target: 
ifeq ($(TEST),"TRUE")
        echo "Do something"
endif
make'e ortam değişkeni şöyle geçilebilir.
$ make TEST=TRUE
make: Nothing to be done for 'test_target'.
Değişkene Değeri Kabuk Programı Çağırarak Atama
Bazen değişkene değeri kabuk programı çağırarak değer atamak gerekir. Shell metodu ile yaparız.
now=$(shell date)



21 Aralık 2015 Pazartesi

pthread_self() ile gettid() arasındaki fark

Not : Bu yazı ile ilgili olarak ACE_Thread_Manager ile yeni thread yaratmak başlıklı yazıya göz atabilirsiniz.

Posix ve Linux Threadleri arasındaki fark

pthread kütüphanesi linux üzerinde glibc tarafından implement edilmiştir. glibc bu gerçekleştirime NPTL (Native Posix Thread Library) adını vermiştir.

pthread kütüphanesinde bulunan pthread_self() metodu bir thread ID değeri döndürmekte ancak bu değer kütüphane tarafından üretilen yapay bir değer. Metodun imzası şöyle.
pthread_t pthread_self(void);
Şöyle kullanırız.
pthread_t tid = pthread_self();
pthread_equal metodu
pthread_t tipinin ne olduğu belirisiz. long'da olabilir bir struct'ta olabilir.
Thread identifiers should be considered opaqueany attempt to use a thread ID other than in pthreads calls is nonportable and can lead to unspecified results.
Thread IDs are only guaranteed to be unique within a process. A thread ID may be reused after a terminated thread has been joined, or a detached thread has terminated.
The thread ID returned by pthread_self() is not the same thing as the kernel thread ID returned by a call to gettid(2).

Dolayısıyla aşağıdaki kod portable olmayabilir.
printf("Thread ID is: %ld", (long) pthread_self());
pthread_t bir çok platformda uintptr_t olarak gerçekleştiriliyor. Bu tipin ne olduğunu bilmeksizin iki pthread_t tipini karşılaştırmak için şöyle yaparız.
pthread_t my_tid; //filled elsewhere

pthread_t tid = pthread_self();

if( pthread_equal(my_tid, tid) ) {
   /* do stuff */
}

gettid metodu
Linux çekirdeği de her thread için bir thread ID değeri üretmekte. Bu değer gettid() metoduyla alınabilir. Metodun imzası şöyle
pid_t gettid(void);
Dikkat edilmesi gereken nokta pthread_self() ile gettid() metodlarını aynı değerleri döndürmezler.
Buradaki soruda da benzer bir cevap var ve gettid() man sayfasından da çok net bir açıklama var.

Linux kernel metodlarını pthread_self()'in verdiği thread ID değeri ile çağıramayız çünkü bu değer pthread kütüphanesine mahsus bir sayı ve Linux çekirdeği bu sayıdan habersiz !

Linux tarafından üretilen thread ID'sini görmek için "ps -L" metodunu kullanırsak buradan aldığım örnekteki gibi bir şey görürüz.



Aradaki farkı vurgulamak için boost thread kütüphanesindeki native_handle() metoduna da dikkat etmek gerekir Bu metod ile yukarıda bahsettiğim işletim sistemi tarafından verilen değeri alabilmek mümkün. 

Bir çok POSIX metodu pthread_self() metoduna ihtiyaç duymaktadır. Örneğin pthread_setaffinity_np metodu için aşağıdaki kod parçası kullanılabilir.

#include "pthread.h"
#include "sched.h"

int affinity = 3; //core id
pthread_t mythread = pthread_self();
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(affinity, &cpuset); //lets kernel know only core affinity may run this thread
if (pthread_setaffinity_np(mythread, sizeof(cpu_set_t), &cpuset) <0){
    perror("sched_set_affinity");
}

20 Aralık 2015 Pazar

Vektor Harita

Raster (Piksel/Izgara) Veri Nedir?
Açıklaması şöyle
At a high level, rasterization refers to the process of converting any two-dimensional digital content to a pixel-based image
Açıklaması şöyle
Piksellerden oluşan, imajlar şeklinde sunulan mekânsal verilerdir. Her bir piksel bir renge karşılık gelerek imajları oluşturur. Örnek verirsek uydu görüntüleri, hava fotoğrafları raster formatında saklanırlar. Raster veriler genelde vektör veriler için altlık olarak kullanılır.
Vector ve Raster Arasındaki Fark Nedir
Açıklamanın bir kısmı buradan geldi
Vektör çizimler noktalardan ve çizgilerden oluşur ve ne kadar büyütme gerçekleştirilirse gerçekleştirilsin her hangi bir bozulma olmaz. Raster, yani Piksel ise belli bir boyutta olup her hangi bir büyütme gerçekleştirildiğinde bozulmalar olacaktır. Vektör çizimler point, contour, polygon gibi şeyleri göstermek için kullanılır.

Raster veriler hücresel verilerdir. Her hücrenin coğrafi konumu ve hücre matrisindeki konumunu verir.Veri depolarken analizi ve programlaması kolaydır. Raster veri ise haritayı belli bir renk kullanarak gösterme, örneğin ormanlık alanı yeşil tonlarını kullanarak gösterme gibi şeylerde kullanılır
Vektör Harita Kaynakları Nelerdir?
Vektör haritalar geometrik şekilleri (nokta, çizgi, poligon vs. gibi) içeren haritalardır. Vektör harita veri kaynakları ESRI Shape File (SHP) ve Vector Product Format (VPF) formatında oluyorlar.
 
VMAP Nedir ?
VMAP (Vector Map - VMAP) tüm dünyanın coğrafi koordinatlarını içeren bir harita. Coğrafi bilgi sistemlerinde iki türlü harita kullanılıyor. Bunlar vektör harita veya raster harita.

Not : VMAP ile bir çok katman geliyor. Eğer sadece politik sınırları görmek istiyorsak buradaki soruya bakılabilir. GADM2 (Global Administrative Areas) kullanılması tavsiye edilmiş.

Kaynak 
Bu haritalar National Geospatial Intelligence Agency verilerine dayanılarak hazırlanmış.

Çözünürlük
Haritalar Çözünürlüğüne göre VMAP0 (en düşük çözünrülük, 1:1,000,000 ölçeğinde, yani. 1cm=10km.) , VMAP1 (orta düzey çözünürlük) gibi sınıflandırılıyor. VMAP0 haritalar public domain olarak halkın kullanımına açılmış.VMAP1 seviyesinde ise dünyanın bazı bölgeleri public domain olarak kullanıma açılmış durumda.

Dosya Formatı
Dosyalar Vector Product Format (VPF ) formatında kaydedilmiş durumda. VPF aslında MIL-STD-2407 Amerikan askeri standardından geliyor. Bu standardın amacı bir çok kaynak tarafından üretilen coğrafi bilginin belli bir format altında saklanması. Yani benzetme yapacak olursak herkesin yazdığı tüm yazıları MS Word 2007 formatı kullanarak kaydetmesi ve dağıtması gibi bir amaç güdüyor.

Ancak daha sonra bu standart görüldüğü gibi başka alanlarda da kullanım bulmuş.

Ancak coğrafi bilgi sistemlerinde daha çok ESRI Shapefile formatı kullanıldığı için bu formata çevirilmiş hazır VMAP0 haritaları da bulunmakta.

MapPoint, KLM gibi daha bir çok dosya formatı bulunuyor ancak bu formatlarda hazır VMAP0 dosyası varmı bilmiyorum.

VMAP0 ile ilgili güzel bir site'yi burada buldum.Aşağıda aynı siteden aldığım ve açılmış bir "Avrupa-Kuzey Asya" haritasının içeriğini gösteren bir şekil var.


Unutulmaması gereken bir nokta ise VMAP haritalarında kullanılan dosya uzantılarının anlamları. Aşağıya dizinlerde bulunan dosyaların anlamlarını gösteren bir tablo koyuyorum.
  • Point Feature Table - .pft
  • Node Feature Table - .pft
  • Line Feature Table - .lft
  • Area Feature Table - .aft
  • Text Feature Table - .tft
Örneğin bnd dizininde (boundaries kelimesinin kısaltması) sınırları line olarak gösteren a.pft vede aynı zamanda sınırları alan olarak gösteren a.aft gibi dosyalar bulunabilir.


Askeri Yazılımlar
 VMAP0 haritalarının bazı askeri yazılımlarda kullanılıyor. Muhtemelen tüm dünyayı kabaca da olsa gösteren bir harita yeterli olduğu içindir.

S57 Nedir ?
S57 diğer ismiyle Hydrographic data transfer, deniz kuvvetlerinin kullandığı harita formatı. Bu formatın şifrenlenmiş haline S63 deniyor.Haritada gösterirken S52 sembolojisi kullanılabilir.

ESRI Formatı
ESRI Formatı yazısına taşıdım.

Kendi Haritamız
Aşağıda küçük bir harita tasarımı var.
Projection ile ilgili notlarım aşağıda.

Google Maps
Google Maps ile bir çok alt API ailesi geliyor. Bunlardan bazıları şunlar
  • Geocoding API
  • Geolocation API
  • Directions API
  • Places API
Data Layer
Polygon eklemek için map.data.addGeoJson() kullanılır

Harita Yaratma
Javascript Google Map Sınıfı yazısına taşıdım.

Çember Ekleme
Şöyle yapılır
CircleOptions co = new CircleOptions();
co.center(point);
co.radius(distance);
co.strokeColor(getResources().getColor(R.color.light_blue));
co.strokeWidth(2.0f);
co.fillColor(Color.parseColor("#8CFFFFFF"));
googleMap.addCircle(co);
URL ile Sorgulama

Google maps il verilen koordinat hakkında bilgi almak mümkün. Örneğin koordinatın hangi ülkeye düştüğü gibi. Örnek:
url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng=22,77&sensor=true';
urlread(url)
Geocoding Nedir?
Verilen adresin GPS koordinatlarına çevrilmesidir. Çevrimin sonucu null veya Approximate gibi bir değer olabilir.

Reverse Geocode Nedir?
Reverse geocode verilen GPS koordinatlarının adrese döndürülmesidir.