Title: Ezamanl Programlama - �lemler aras iletiim

ArticleCategory:

Software Development

AuthorImage:[Here we need a little image from you]

[Leonardo]

TranslationInfo:

original in it Leonardo Giordani

it to en: Leonardo Giordani

en to tr  �can Gngr

AboutTheAuthor:

Milan,Politecnico'da Telekominikasyon Fakltesi'nde renci.Netwok yneticilii yapyor ve programlama ( zellikle assembly ve C++) ile ilgileniyor.1999'dan beri zellikle Linux/Unix zerinde �lyor.

Abstract:

Bu makale dizisinin amac, okuyucuya �kluilemler ve onun Linux'ta uygulan hakknda bilgi vermektir.Teorik bilgilerden balayp ilemler aras iletiim rnei gsteren tamamlanm bir rnek vereceiz.Basit ama etkili bir iletiim protok kullanacaz.
Makalenin anlalabilmesi i�n u bilgilere gereksinim vardr: �celikle Kasm 2002,makale 272 'yi okumalsnz �nk bu makalenin devamdr.

ArticleIllustration:

[run in paralell]

ArticleBody:

Giri

Burada Linux'ta �kluilemleri a�klayacaz.Bir nceki makalede grdmz gibi bir programn �lmasn blmek i�n bir ka�kod satr yeterlidir.�nk iletim sistemi yarattmz ilemlerin balang�, ynetilmesi ve zamanlamasyla ilgilenir.
�letim sistemi tarafndan salanan servis biricil neme sahiptir, o ilemlerin "�lma yneticisi"dir.Yani ilemler belirli bir ortamda �ltrlr.�lemler �lrken  kontrolnn kayb, programcya ezamanllk sorunu getirir.�gilendiimiz soru udur:�i bamsz ilemi nasl bir arada �ltabiliriz?
Sorun sandmzdan daha karktr:Sorun sadece iki ilemin ezamanlamas deil. Veri paylam ve okuma-yazma da sorundur.
Sradan bir ezamanlama sorusu dnelim:Eer iki ilem ayn anda bir veri kmesini okuyacaksa sorun yoktur.�lma bi�mlerinde deiiklik olmaz ve hep ayn sonucu retirler.�mdi ilemlerden birinin veri kmesini deitirmek istediini dnelim.�inci ilemin ilk ilemden nce ya da sonra �lmasna gre verecei sonu�farkl olacaktr.�enin:"A" ve "B" iki ilemimiz ve "d" bir tam say olsun.A ilemi d'yi 1 artrr.B ise d'yi ekrana yazdrr.Bunu u ekilde ifade edebiliriz:

A { d->d+1 } & B { d->output }

Burada "&" ezamanal ilemi ifade eder.Birinci mmkn �lma:

(-) d = 5 (A) d = 6 (B) output = 6

ama eer nce B �lrsa unu elde ederiz :

(-) d = 5 (B) output = 5 (A) d = 6

Bu rnekten ezamanal �lmann doru ynetilmesinin nemini anlyorsunuz.Verilerin ayn olmamas riski byktr ve kabul edilemez.Bu veri kmelerinin banka hesaplarnz olduunu dnn.Bu sorunu asla k�msemezsiniz.
Bir nceki makalede waitpid(2) fonksiyonu kullanarak ezamanlamann ilk bi�mini grmtrk.Bu fonksiyon, bir ilemin devam etmeden nce baka bir ilemin bitmesi i�n  beklemeye yarar.Aslnda bu, okuma-yazma annda oluabilecek karmakl byk l�de engeller.Bir veri kmesi zerinde P1 �lyorsa, P2 ayn veri kmesinde veya bir alt kmesinde �lacaksa nce P1'in bitmesini beklemek zorundadr.
A�kca bu yntem bir �zmdr.fakan en iyisi deildir.P2, P1'in ileminin bitmesi i�n -�k ksa srecekse bile- uzun zaman bekleyecektir.Biz kontrolmzn alann daraltmalyz.�nein:tek bir veriye ya da  veri kmesine erime gibi.Bu sorunun �zm ktphanelerin temeli olan,SysV IPC(System V InterProcess Communication-SistemV �lemleraras �etiim) ad verilen bir takm ktphane ile verilir.

SysV Anahtarlar

Ezamanllk ve onun uygulamalr ile ilgili teorilere girmeden nce tipik SysV yapsna bir gz atalm:IPC anahtarlar.Bir IPC anahtar, bir IPC kontrol yapsn (daha sonra a�klanacaktr) belirleyen bir saydr.Ancak bu, ayn tip belirleyicileri retmek i�n de kullanlr.�enein: no-IPC yaplarn organize etmek i�n.Bir anahtar ftok(3) fonksiyonu kullanlarak oluturulur:

key_t ftok(const char *pathname, int proj_id);

Bu fonksiyon, var olan bir dosya adn (pathname) ve bir tam say kullanr.Anahtarn tek olacann garantisi yoktur �nk dosyadan alnan parametreler (i-node says ve src numaras), benzer kombinasyonlar  oluturabilir.Var olan anahtarlar kontrol eden ve ayn anahtarn kullanmasn engelleyecek k�k bir ktphane oluturmak iyi bir �zm olacaktr.
 

Semaforlar

Ara�trafiinde kullanlan semaforlar hi�deitirilmeden veri ak kontrolnde de kullanlabilir.Bir semafor, sfr vaya daha byk bir deer alan ve semafordaki bir koulun ger�klemesini bekleyen ilem kuyruunu yneten bir yapdr.Semaforlarn basit gibi grnmelerine karn �k g�drler.Hata kontroln darda brakarak balayalm:Semaforlar kamak programlarla karlatmzda kullanacaz.
Semaforlar kontrol kaynaklarna ularken kullanlabilirler:Semaforun deeri, bir kaynaa ulamaya �lan bir ilemin numarasn gsterir.Bir ilem bir kaynaa her ulamaya �lt zaman semafonun deeri azaltlr ve ilemin kaynakla ii bittiinde tekrar artlr.Eer kaynak zel ise ( sadce bir ilem ulaabiliyorsa ) semaforun balang�deeri 1 olur.
Semafora benzer farkl bir kavram daha vardr: kaynak sayac.Bu deer, bu durumda, ulalabilir kaynak saysn gsterir ( serbest bellek hcre says gibi ).
Ger�k bir durum dnelim.Semafor tipleri kullanlsn:S1,..,Sn ilemlerinin yazma hakk olan ama sadece L ileminin okuma hakk olan bir tampon var.Bu tampon zerinde belirli bir anda sadece bir ilem �labilsin.S ilemlerinin tamponun dolmas dnda her zaman tampona yazabiliriler ve L ilemi sadece tampon bo olmad zaman okuyabilir.Bu durumda �semafora gereksini var:Birincisi kaynaa eriimi ynetir, ikinci ve �nc semafor tampondaki eleman saysn tutar (ileride neden iki semaforun yeterli olmadn greceiz).
Tamponun zel olduunu dnelim.Birinci semafor sadece 0 veya 1 deerini alabilir.�inci ve �nc semaforun alabilecei deer tamponun boyutuna baldr.
�mdi semaforlarn C'de SysV'yi kullanarak nasl uygulandn grelim.Semaforlar oluturan fonksiyon semget(2)'dir:

int semget(key_t key, int nsems, int semflg);

Burada key,IPC anahtardr.nsems, oluturmak istediimiz semafor saysdr.semflg, 12 bitlik eriim kontorldr.�k 3' oluturma politikasna gre deiir, dier 9' ise kullanc, group ve dierlerinin (Unix dosya sistemindeki gibi) okuma ve yazma haklardr.Tam a�klama i�n ipc(5)'nin kullanma klavuzunu okuyun.Farkettiiniz gibi SysV bir semafor kmesini kontrol eder ve bu sebeple kod daha k�ktr.
�k semaforumuzu oluturalm:

#include <stdio.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/ipc.h>
#include <linux/sem.h>
int main(void)
{
  key_t key;
  int semid;
  key = ftok("/etc/fstab", getpid());
  /* Bir semafor i�en bir semafor kmesi oluturalm */
  semid = semget(key, 1, 0666 | IPC_CREAT);
  return 0;
}

�eride semaforlarn nasl ynetildiini ve silindiini reneceiz.Semaforu ynetme fonksiyonu semctl(2)'dir:

int semctl(int semid, int semnum, int cmd, ...)

Burada parametreler semafor kmesinin veya (istenirse) sadece semnum ile belirtilen semaforun ilevine bal olarak cmd ile verilir.Biz gereksinim duyduk� baz se�nekleri anlatacaz.Ama tm liste kullanma klavuzunda verilmitir.cmd ilevine bal olarak fonksiyon i�n baka parametreler de tamnlamak gerekebilir.� ekildedir:

union semun {
 int val;                  /* SETVAL deeri */
 struct semid_ds *buf;     /* IPC_STAT, IPC_SET i�n tampon*/
 unsigned short *array;    /* GETALL, SETALL i�n dizi*/
                           /* Linux'a zg ksm */
 struct seminfo *__buf;    /* IPC_INFO i�n tampon*/
};

Semafora deer verebilmek i�n SETVAL ynergesi kullanmladr ve bu deer semun birliinde (union) belirtilmelidir:Bir nceki programdaki semforun deerini 1 yapalm:

[...]
  /* Bir semaforlu bir semafor kmesi olutur */
  semid = semget(key, 1, 0666 | IPC_CREAT);
  /* 0 numaral semaforun deerini 1 yap */
  arg.val = 1;
  semctl(semid, 0, SETVAL, arg);
[...]

�mdi semafor i�n ayrlm yeri boaltmamz gerekiyor.Bu ilem, semctl fonksiyonunda IPC_RMID ynergesi ile yaplr.Bu ilem semaforu siler ve bu kaynaa ulamak i�n bekleyen  butn ilemlere bir ileti gnderir.Yukardaki programn devam olarak:

[...]
  /* Semafore 0'in deerini 1 yap */
  arg.val = 1;
  semctl(semid, 0, SETVAL, arg);
  /* Semaforu sil */
  semctl(semid, 0, IPC_RMID);
[...]

Daha nce de grdmz gibi ezamanl ilerleri oluturmak ve ynetmek zor deildir.Hata ynetimi iin i�ne girdiinde, kodun karmakll a�sndan iler biraz zorlaacak.
Artk semafor semop(2) fonksiyonu ile kullanlabilir:

int semop(int semid, struct sembuf *sops, unsigned nsops);

Burada semid, kmenin belirteci; sops, yaplacak ilemler dizisi ve nsops bu ilemlerin saysdr.Btn ilemler sembuf yapsyla temsil edilir:

unsigned short sem_num; short sem_op; short sem_flg;

�nein kmedeki semaforun numaras (sem_num), ilem (sem_op) ve bekleme politikasn ayarlayan bayrak (imdilik sem_flg 0 olsun).Belirleyeceimiz ilemler tam saylardr ve aadaki kurallara uyar:
 

  1. sem_op < 0

  2. Eer semaforun mutlak deeri sem_op' eit veya sem_op'dan bykse, ilem devam eder ve semaforun deerine sem_op eklenir.Eer semaforun mutlak deeri sem_op'dan k�kse, ilem belirli bir kaynak numars ulalabilir olana kadar uyku durumuna ge�r.
  3. sem_op=0

  4. �lem, semaforun deeri 0 oluncaya kadar uyku durumuna ge�r.
  5. sem _op > 0

  6. sem_op deeri, semaforun deerine eklenir ve daha nce kullanlan kaynak braklr.
Aadaki program, semaforlarn nasl kullanlacan gteriri.Ayrca daha nce verdiimiz tampon rneinin kulanmn da gsterir:Biz be adet Y (yazma) ve bir adet O (okuma) ilemi outuracaz.Her Y ilemi semafor kullanarak eriecei kayna (tampon) kilitleyecek.Eer tampon dolu deilse, tampona bie eleman koyacak ve tamponu brakacaktr.O ilemi, tamponu kilitler, tampon bo deilse bir eleman alr ve kilidi kaldrr.
Neden �semafora gereksinimimiz var?�ki (0 numaral semafor), tamponun eriim kilididir ve en byk deeri 1'dir.Dier iki semafor doluluu ve boluu temsil eder.
Durumu daha a�k anlatalm: bir semaforumuz (ad O olsun) olsun ve tampondaki bo yerin deerini tutsun.Bir S ilemi her tambona birey koyduunda bu deer 1 azalr.Ve bu sfr deeri alncaya kadar devam eder yani tampon dolana kadar.Bu semafor boluu temsil edemez: R ilemi kendi deerini snrsz artrabilir.Bundan dolay baka bir semafora (ad U olsun) gereksinim duyarz.Bu semafor tampondaki eleman saysn tutar.W ilemi her tampona bir eleman koyduunda, W'nun deerini artrr ve O'nun deerini azaltr.Tersi durumda, R ilemi, U'nun deerini azaltr ve O'nun deerini artrr.

Doluluk, O semaforunun deerini artamamak ile; boluk, U semaforunu deerini azaltamamak ile anlalr.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/types.h>
#include <linux/ipc.h>
#include <linux/sem.h>
int main(int argc, char *argv[])
{
  /* IPC */
  pid_t pid;
  key_t key;
  int semid;
  union semun arg;
  struct sembuf lock_res = {0, -1, 0};
  struct sembuf rel_res = {0, 1, 0};
  struct sembuf push[2] = {1, -1, IPC_NOWAIT, 2, 1, IPC_NOWAIT};
  struct sembuf pop[2] = {1, 1, IPC_NOWAIT, 2, -1, IPC_NOWAIT};
  /* Dierleri */
  int i;
  if(argc < 2){
    printf("Kullanm: bufdemo [boyut]\n");
    exit(0);
  }
  /* Semaforlar */
  key = ftok("/etc/fstab", getpid());
  /* 3 semafor i�ren semafor kmesi olutur */
  semid = semget(key, 3, 0666 | IPC_CREAT);
  /* Semaphore #0'n deerini  1 yap - Kaynak kontrol */
  arg.val = 1;
  semctl(semid, 0, SETVAL, arg);
  /* Semafor #1'in deerini buf_length yap- Doluluk kontrol */
  /* Sem'in deeri 'tampondaki bo yer'dir */
  arg.val = atol(argv[1]);
  semctl(semid, 1, SETVAL, arg);
  /* Semafor #2'nin deeri buf_length'dir - Boluk kontrol */
  /* Sem'in deeri 'tampondaki eleman says'dr */
  arg.val = 0;
  semctl(semid, 2, SETVAL, arg);
  /* Ayrma */
  for (i = 0; i < 5; i++){
    pid = fork();
    if (!pid){
      for (i = 0; i < 20; i++){
 sleep(rand()%6);
 /* Kayna kilitlemeyi dene - sem #0 */
 if (semop(semid, &lock_res, 1) == -1){
   perror("semop:lock_res");
 }
 /* Bir serbest boluu kilitle - sem #1 / Bir eleman koy - sem #2*/
 if (semop(semid, &push, 2) != -1){
   printf("---> �lem:%d\n", getpid());
 }
 else{
   printf("---> �lem:%d  TAMPON DOLU\n", getpid());
 }
 /* Kayna brak */
 semop(semid, &rel_res, 1);
      }
      exit(0);
    }
  }
  for (i = 0;i < 100; i++){
    sleep(rand()%3);
    /* Kayna kilitlemeyi dene - sem #0 */
    if (semop(semid, &lock_res, 1) == -1){
      perror("semop:lock_res");
    }
    /* Serbest boluun kilidini kaldr - sem #1 / Bir eleman al - sem #2 */
    if (semop(semid, &pop, 2) != -1){
      printf("<--- �lem:%d\n", getpid());
    }
    else printf("<--- �lem:%d  TAMPON BO�n", getpid());
    /* Kayna brak */
    semop(semid, &rel_res, 1);
  }
  /* Seamforlar sil */
  semctl(semid, 0, IPC_RMID);
  return 0;
}

Koddaki u ilgin�satlara bakalm:

struct sembuf lock_res = {0, -1, 0};
struct sembuf rel_res = {0, 1, 0};
struct sembuf push[2] = {1, -1, IPC_NOWAIT, 2, 1, IPC_NOWAIT};
struct sembuf pop[2] = {1, 1, IPC_NOWAIT, 2, -1, IPC_NOWAIT};

Bu drt satr, semaforlar zerinde yapabileceimiz ilemlerdir: �k ikisi tek ilem iken dier iki ilem �ft ilemdir.�k ilem, lock_res, kayna kilitmeyi dener:Bu ilem ilk semaforun (0 numaral) deerini -eer semaforun deeri sfr deilse- bir azaltr.Kaynan kilitli olmas durunda politika hi�iri deildir (rnein ilem bekleme durumunda).rel_res, lock_res'e benzer ama kaynak braklr( deeri pozitiftir) .
Ekleme ve �karma ilemleri biraz zeldir.Bunlar iki ilem dizisidir.Birincisi 1 numaral semafor zerinde ve ikincisi 2 numaral semafor zerindedir.Birincisi artrma iken ikincisi azaltmadr veya tam tersi.Ama politika artk bekleme durumu deildir:IPC_NOWAIT, ilemi, kaynak kilitli ise �lmasna devam etmesi i�n zorlar.

/* Semafo #0'in deerini 1 yap - Kaynak kontrol */
arg.val = 1;
semctl(semid, 0, SETVAL, arg);
/* Semafor #1'i  buf_length yap - Doluluk kontrol */
/* Sem'in deeri  'tampondaki bo yer'dir */
arg.val = atol(argv[1]);
semctl(semid, 1, SETVAL, arg);
/* Semafor #2'yi buf_length yap - Boluk kontrol */
/* Sem'in deeri 'tampondaki eleman says'dir */
arg.val = 0;
semctl(semid, 2, SETVAL, arg);

Burada semaforlara ilk deerlerini veririz..Birincisini 1 yaparz �nk belirili bir kaynaa ulamay kontrol eder.�incisini, tamponun uzunluuna eitleriz.�ncsn ise boluk ve doluluu gsterir.

/* Kayna kilitlemeye �l - sem #0 */
if (semop(semid, &lock_res, 1) == -1){
  perror("semop:lock_res");
}
/* Bir bo yer kilitle - sem #1 / Bir eleman koy - sem #2*/
if (semop(semid, &push, 2) != -1){
  printf("---> �lem:%d\n", getpid());
}
else{
  printf("---> �lem:%d  TAMPON DOLU\n", getpid());
}
/* Kaynaktaki kilidi kaldr */
semop(semid, &rel_res, 1);

Y ilemi, kayna lock_res fonksiyonunu kullanarak kilitlemeya �lr.Bunu ger�kletirdikten sonra kaynaa bir eleman koyar ve bunu ekrana yazar.Eer bu ilemi yapamazsa ekrana "TAMPON DOLU" iletisini yazar.Daha sonra kayna serbest brakr.

/* Kayna kilitlemeyi dene - sem #0 */
    if (semop(semid, &lock_res, 1) == -1){
      perror("semop:lock_res");
    }
    /* Serbest boluun kilidini kaldr - sem #1 / Bir eleman al - sem #2 */
    if (semop(semid, &pop, 2) != -1){
      printf("<--- �lem:%d\n", getpid());
    }
    else printf("<--- �lem:%d  TAMPON BO�n", getpid());
    /* Kayna brak */
    semop(semid, &rel_res, 1);

O ilemi, az �k Y kadar �ltrlr:Kayna kilitler, bir eleman alr ve kayna serbest brakr.

Bir sonraki  makalede, ileti kuyruklarndan, �lemleraras �etiimin ve ezamanlamann farkl bir yapsndan bahsedeceiz.Bu makaleyi kullanarak yazdnz programlar -basit olsalar bile- bana da gnderin ( isim ve e-posta adreslerinizle birlikte ).Bunlar okumaktan memnun olacam.�i �lmalar.
 

�erilen Kaynaklar