Görevler Arası Zamanuyumlama Ahmet Burak Can Hacettepe Üniversitesi abc@cs.hacettepe.edu.tr Birlikte Çalışan Görevler Bilgisayar kaynaklarının etkin kullanımı için, görevlerin birlikte ve koşut işlemi zorunludur. Gerçek koşutluk Görüntü koşutluk Koşut işlem, görevler arasında kaynak paylaşımı ve zaman uyumlama sorunlarını beraberinde getirir. Birlikte çalışan görevler arası etkileşim, çoğu kez kaynak paylaşımından doğar. 1 2 Üretici/Tüketici Görev Örneği Kaynaklara Erişim 3 Bölüşülür Kaynaklar: Ana işlem birimi, ana bellek, disk birimi Bölüşülmez Kaynaklar: Yazıcı, görevler arası ortak yastık alanları İki görev, bir ortak kaynağa erişim 4 biçimde gerçekleştirebilir: Okuma Okuma Okuma Yazma Yazma Okuma Yazma Yazma Sadece Okuma Okuma durumunda iki görev aynı anda ortak kaynağa erişebilir. 4 Kritik Kaynaklar İşletim Bütünlüğünün Bozulması - Örnek 1 Bölüşülmez kaynaklar kritik kaynaklar olarak adlandırılır. Kritik kaynaklara erişmeden önce, kaynağın kullanım durumunun sınanması ve diğer görevlerin o anda kaynak üzerinde işlem yapmadıklarından emin olunması gereklidir. Örnek: Sistem saati üzerinde çalışan 3 görev Saat: Gerçek zaman saati kesilmelerini işleyip sistem saatini günler. Yani belirli vuru aralıklarında üretilen saat kesilmesiyle çağrılır. Göster: Sistem saatini görüntülemeye yarar Öndeğerata: Sistem saatini sıfırlamayı sağlar. 5 6
İşletim Bütünlüğünün Bozulması - Örnek 2 İşletim Bütünlüğünün Bozulması - Örnek 2 Yukarıdaki gibi tek bağlaçlı listeye öğe eklemek için aşağıdaki gibi bir kod kesimi çalıştırılır: yeniöge.bağ ilköge = ilköge; = ¥iöge; Birden fazla görev bu listeye ekleme yaptığında nasıl bir problem oluşabilir? 7 8 Kritik Kesimler Kritik Kesime Erişim Kritik kaynağa erişim yapan program kesimleri kritik kesimler olarak adlandırılır. Kritik kaynağa aynı anda en çok bir görevin erişebilmesi, kritik kaynağa erişim yapan görevlerden en çok birinin kritik kesimi içinde bulunmasıyla sağlanabilir. Buna karşılıklı dışlama denir. Karşılıklı dışlama görevlerin kritik kesimlerine giriş ve çıkışlarında alınan önlemler yoluyla gerçekleştirilir. Görevlerin, birbirlerinin işletimlerini karşılıklı olarak, sürekli engellemelerine karşılıklı tıkanma denir. Karşılıklı dışlamayı sağlamanın yanında karşılıklı tıkanmanın engellenmesi gerekir. 9 10 Görevler Arası Zamanuyumlama Kuralları 1. Karşılıklı dışlamanın sağlanması: Birlikte çalışan görevlerden en çok biri, aynı anda kritik kesimine girebilmelidir. 2. Karşılıklı tıkanmanın engellenmesi: Aynı anda ortak kaynağa erişmek isteyen görevlerden en az biri, sonlu bir süre için kritik kesimine girebilmelidir. 3. Kritik kesiminin dışındaki görevler ortak kaynağa erişmek isteyen görevleri engellememelidir. 4. Görevlerin göreli hız ve öncelikleri ile sistemde yer alan AİB sayısı hakkında herhangi bir varsayım yapılmamalıdır. Kesilme Düzeneği Kullanımı Karşılıklı dışlamayı sağlamak üzere, bir görev kritik kesimine girerken sistemi kesilmelere kapayabilir. Örnek: Sistem saatine erişen görevlerin kesilme ile engellenmesi. Göster: cli; saniye1=saniye; dakika1=dakika; saat1=saat; sti; Öndeğerata: cli; saat=0; dakika=0; saniye=0; sti; 11 12
Kesilme Düzeneği Kullanımı Kesilme düzeneği kullanımının en önemli sakıncaları nelerdir? Sistemin kesilmelere kestirilemez uzunlukta kapalı kalmasına ve bu sebeple işletim bütünlüğünü zedeleyecek durumlara neden olabilir. AİB tüm dış uyarılara kapatılır ve kritik kaynakla ilgisi olmayan görevlerin de işletimlerini engeller. Kesilme düzeneğinin denetimini sistemde çalışan çok sayıda göreve, özellikle çekirdek katman dışındaki görevlere de dağıtmasıdır. Algoritmik Yaklaşım Örnek 1 GÖREV 1 GÖREV 2.. while(sıra!=1); /*bekle*/ while(sıra!=2); /*bekle*/ kritik-kesim-1(); kritik-kesim-2(); sıra=2; sıra=1;.. Problem: Kritik kesim dışındaki görev, sıra kendindeyse, kritik kesime girmese bile diğer görevin kritik kesime girmesine izin vermeyebiliyor. 13 14 Algoritmik Yaklaşım Örnek 2 GÖREV 1 GÖREV 2.. while(durum==0);/*bekle*/ while(durum==0);/*bekle*/ durum=0; durum=0; kritik-kesim-1(); kritik-kesim-2(); durum=1; durum=1;.. Algoritmik Yaklaşım Örnek 2 GÖREV 1 GÖREV 2.. bekle1:cmp durum, 0 bekle2:cmp durum, 0 jz bekle1 jz bekle2 mov durum, 0 mov durum, 0 [Kritik Kesim-1] [Kritik Kesim-2] mov durum,1 mov durum,1.. Durum değişkenini sınama ve değiştirme işlemi tek adımda yapılamamakta. test-and-set türü komutlara ihtiyaç duyulmaktadır. 15 16 test-and-set Komutları Görevlerin kritik kesimlerine girerken, aşağıdaki gibi ortak bir değişkeni sınama ve günleme işlemlerini, bölünmez bir biçimde, tek adımda yapabilmesi gereklidir. bekle-i: cmp durum, 0 jz bekle-i mov durum, 0 test-and-set türü komutlar bir değişkeni sınama ve günleme işlemlerini donanımsal olarak tek adımda yaparlar. test-and-set komutları test-and-set türü komutlar genelde iki işlenen içerirler. Genel sözdizimi şöyledir: ts reg, durum İşlenenlerden biri (durum), ortak kaynağın kullanım durumunu gösteren ve birlikte çalışan görevlerin hepsinin paylaştığı genel bir ana bellek değişkenidir. Diğer işlenen ise (reg) göreve özel bir yazmaç olabilir. 17 18
test-and-set Kullanımı GÖREV-Đ bekle-i:... ts al, durum cmp al,0 jz bekle-i Kritik Kesim-i mov durum, 1 Diğer Đşlemler-i DİKKAT: Kitaptaki örnek değiştirildi. Kitaptaki örnekte, durum değişkeni 1 iken kritik kaynak meşgul sayılıyordu. Bu örnekte durum değişkeni 0 olduğu zaman meşgul olduğu varsayılıyor. ts komutunun durum değişkenine sıfır değeri yüklediğini varsayınız. Intel 80x86 da xchg Komutu xchg komutu, ts komutu örneklenirken belirtildiği gibi, iki işleneni olan bir komuttur. xchg dest, src Bu işlenenlerden biri mutlaka bir yazmaç, diğeri ise herhangi bir değişken ya da başka bir yazmaç olabilmektedir. Komut işletildiğinde: temp <-- dest dest <-- src src <-- temp işlemlerini bölünmez biçimde gerçekleştirmektedir. temp, programlanır yazmaçlar arasında yer almayan ve geçici olarak değer saklamaya yarayan bir yazmacı simgelemektedir. 19 20 Intel 80x86 da xchg Kullanımı GÖREV-Đ... bekle-i: mov al, 0 xchg al, durum cmp al, 0 jz bekle-i Kritik Kesim-i mov durum, 1 Diğer Đşlemler-i DİKKAT: Kitaptaki örnek değiştirildi. Kitaptaki örnekte, durum değişkeni 1 iken kritik kaynak meşgul sayılıyordu. Bu örnekte, durum değişkeni 0 olduğu zaman meşgul olduğu varsayılıyor. Çok İşleyicili Bilgisayarlarda test-andset İşlemleri ts ve xchg komutları, tek AİB içeren sistemlerde zamanuyumlamayı gerçekleştirmede yeterlidir. Birden çok AİB bulunduran çok işleyicili bir sistemlerde, bu komutlar karşılıklı dışlamayı sağlamada yetersiz kalır. Bir işleyici ortak belleğe erişirken, diğer bir işleyici bunun erişimini bölerek aynı bellek sözcüğüne koşut olarak erişebilir. Çok işleyicili sistemlerde ortak bellek üzerinde koşut erişilen zamanuyumlama değişkenlerinin eşanlı erişimlere karşı korunması gereklidir. 21 22 Çok İşleyicili Bilgisayarlarda test-andset İşlemleri 80X86 serisi işleyicilerde, komutların başına önek olarak konulan lock sözde komutu bu amaçla kullanılır. lock önekiyle bir komutu çalıştıran işleyicinin bellek erişim döngüsünün bölünmesine izin verilmez. Bellek erişiminin kilitlenmesini kendiliğinden yerine getiren komutlar olarak tsl (test and set lock) simgesiyle de anılmaktadırlar. Örnek: 80386'dan başlayarak Intel 80X86 işleyicilerinde xchg komutu Motorola 680X0 serisi işleyicilerde tas (test-and-set) komutu IBM System/370 serisi bilgisayar sistemlerinde kullanılan compare-and-swap komutu İlkel Semafor Kullanımı Dijkstra, iki ya da daha çok görev arasında karşılıklı dışlamayı sağlayacak, semafor (S) adlı özel, pozitif tamsayı değişkenler üzerinde işlem yapan P (S) ve V (S) adlı ilkel işleçleri tanımlamıştır. Bunların ilkel işleçler olmaları, işletimlerinin bölünemediği anlamına gelir. P(S); bölünmez (atomik) biçimde S değişkenini sınayan eğer S sıfırdan büyükse içeriğini bir eksilten, değilse beklemeyi sağlayan bir işleç tanımı içerir. V(S) ise S değişkenini bir artırmayı sağlayan bir işleç olarak tanımlanır. 23 24
Semafor Tanımı ve Kullanımı Semaforla Üretici/Tüketici Görev Programlanması P(S) ve V(S) işleçleri tanımı: P (int *S) while(*s <= 0); /*bekle/ (*S)--; V (int *S) (*S)++; Semaforun program içinde kullanımı:. P(S); Kritik Kesim V(S);. 25 Çözüm: Görevlerin yastığa erişip erişmediğini kontrol etmek için bir semafor tanımlanır. 26 Semaforla Üretici/Tüketici Görev Programlanması P(S) ve V(S) İşleçlerinin Kuyruk Kullanarak Etkinleştirilmesi int b; boolean dolu=false; kullanıcı() char tutanak [80]; while(true) P (b); if (!dolu) çıktı-üret(tutanak); yastığayaz(f,tutanak); dolu = true; V (b); yazıcı() char tutanak [80]; while(true) P (b); if (dolu) yastıkoku(f,tutanak); dök(tutanak); dolu=false; V (b); 27 28 Semafor Kuyrukları Görevler Arası Akış Denetimin Sağlanması 29 30
80x86 Makina Dilinde Semafor Gerçekleştirimi 80x86 Makina Dilinde Semafor Gerçekleştirimi P macro durum,durum-kuyruğu local yine,eriş yine: mov al, 0 lock xchg al, durum cmp al, 0 jnz eriş suspend(görev-kimliği,durum-kuyruğu) jmp yine eriş: P endm V son: V macro durum,durum-kuyruğu local son mov durum,1 mov dl, durum-kuyruğu mov al, 07h int 01ch ;al <-- kuyruk başındaki görev kimliği or al,al ;al = 0 ise kuyruk boş demektir. jz son mov kimlik, al resume(kimlik, durum-kuyruğu) endm 31 32 80x86 Makina Dilinde Semafor Gerçekleştirimi Sayan Semaforlar suspend suspend resume resume macro görev-kimliği,kuyruk kimliği,kuyruk-kimliği mov dl, görev-kimliği mov dh, kuyruk-kimliği mov al, 05h int 01ch endm macro görev-kimliği,kuyruk kimliği,kuyruk-kimliği mov dl, görev-kimliği mov dh, kuyruk-kimliği mov al, 06h int 01ch endm Semafor işleçleri, eksi tamsayıları da kapsayacak işleçler biçimine dönüştürüldüğünde, ilgili semafor için bekleyen görev sayısını (kuyruk boyunu) belirlemek mümkündür. Eksi tamsayı değerleri de alabilen semaforlar sayan semaforlar ya da genel semaforlar olarak adlandırılır. 33 34 Sayan Semaforla Üretici/Tüketici Görev Programlanması Sayan Semaforla Üretici/Tüketici Görev Programlanması Yastığın dolup dolmadığını kontrol etmek için iki sayan semafor tanımlanır: Bir semafor (f) doluluk oranını, diğeri boşluk (e) oranını sayar. Program başında boşluk sayan semafor (e) yastık boyuna, diğeri (f) sıfıra eşitlenir. int b,e,f; kullanıcı() char tutanak [80]; while(true) çıktı-üret(tutanak); P (e); P (b); yastığayaz(f,tutanak); V (b); V (f); yazıcı() char tutanak [80]; while(true) P (f); P (b); yastıkoku(f,tutanak); V (b); V (e); dök(tutanak); 35 36
Uyuyan Berber Problemi (Sleeping Barber) Uyuyan Berber Problemi için Çözüm #define CHAIRS 5 /* # of chairs for waiting customers */ typedef int semaphore; /* use your imagination */ semaphore customers = 0; /* # of customers waiting for service */ semaphore barbers = 0; /* # of barbers waiting for customers */ semaphore mutex = 1; /* for mutual exclusion */ int waiting = 0; /* customers are waiting (not being cut) */ void barber(void) white (TRUE) P(&customers); /* go to sleep if # of customers is 0 */ P(&mutex); /* acquire access to 'waiting' */ waiting = waiting - 1;/* decrement count of waiting customers */ V(&barbers); /* one barber is now ready to cut hair */ V(&mutex); /* release 'waiting' */ cut_hair(); /* cut hair (outside critical region) */ 37 38 Uyuyan Berber Problemi için Çözüm Öncelik Çizgesi ve Birden Fazla Görev Arası Zamanuyumlama void customer(void) P(&mutex); /* enter critical region */ if (waiting < CHAIRS) /* if there are no free chairs, leave */ waiting = waiting + 1; /* increment count of waiting customers */ V(&customers); /* wake up barber if necessary */ V(&mutex); /* release access to 'waiting' */ P(&barbers); /* go to sleep if # of free barbers is 0 */ get_haircut(); /* be seated and be serviced */ else V(&mutex); /* shop is full; do not wait */ 39 40 Üst Düzey Zamanuyumlama Araçları Görevler arası iletişimi alt düzey işleçler yerine, bu işleçlerden yararlanılarak gerçekleştirilen daha üst düzey tanımlara dayalı işlevlerle ele almak programlama kolaylığı sağlayan bir yoldur. Bu amaçla, sistem çağrıları arasında çoğu kez send ve receive olarak adlandırılan işlevler öngörülür. Bu işlevler, görevler arası iletişimin yanı sıra bunun ortaya çıkardığı zamanuyum sorununu da, programcılara yansıtmadan çözerler. send/receive komutları send komutu bir görevin diğer bir göreve ileti göndermesi için kullanılır. receive komutu diğer görevlerden ileti beklemek ve almak için kullanılır. send (hedef, ileti) receive (kaynak, ileti) hedef vekaynak, alan ve gönderen görevlerin kimlikleridir. ileti ise aktarılan veri öbeğini belirler. send komutu, ileti adlı veri öbeğininhedef kimlikli alıcı göreve aktarılmasını; receive komutu ise kaynak kimlikli görevin göndereceğiileti'nin okunmasını sağlar. 41 42
send/receive Kullanımı Örneği send/receive Komutlarının Gerçekleştirimi İletilerin kaynak kimlikli görevden hedef kimlikli göreve aktarımı, değişik yollarla gerçekleştirilebilir: Kaynak görevin bellek alanından, doğrudan hedef görevin bellek alanına aktarılması Sorun: Görevlerin işletimlerini bekle-ilerle biçimiyle yavaşlatan bir yoldur. İşletim sistemine ilişkin yastık alanları üzerinden dolaylı taşınması Sorun: Veri yapılarının tanımları kullanıcılara bırakılmaz. Posta kutularının kullanılması 43 44 Posta Kutusu ile send/receive Gerçekleştirimi Posta kutuları, belirli sayıda ve çoğu kez değişmez uzunlukta iletinin yastıklanmasına yarayan ve görevler programlanırken tanımlanan özel tür yapılardır. Veri yapılarının tanımlarını kullanıcılara bırakma esnekliği posta kutusu kullanımıyla sağlanır. send (posta-kutusu, ileti) send komutu ile posta kutusuna ileti gönderen görev, posta kutusu dolunca, bu posta kutusuna ilişkin bekleme durumuna alınır. receive (posta-kutusu, ileti) receive komutu, varsa bekleme durumundaki görevi hazır göreve dönüştürür. Posta kutusu boşken receive komutu ile ileti okumak isteyen görev, bu kutuya ilişkin bekleme durumuna alınır. UNIX te Posta Kutuları pipe komutu, UNIX işletim sisteminde görevler arası posta kutuları oluşturmak amacıyla kullanılır. Verilerin pipe a gönderilmesi ve alınması, sıradan kütükler için kullanılan yazma ve okuma komutlarıyla gerçekleştirilir. UNIX işletim sisteminde pipe olarak adlandırılan posta kutularının kimlikleri (adları) bulunmaz. Bu nedenle, pipe sadece ata-oğul yakınlığındaki görevler tarafından kullanılabilirler. 45 46 pipe Kullanım Örneği-1 /* cc -o ata a ata.c a.c komutuyla derlenen ana.c */ #include <stdio.h> main() int i, pfd[2], boy; char fdstr[10], msg[80]; pipe(pfd); if(fork()==0) close(pfd[1]); /*cocuk da yazma ucunu kapa*/ sprintf(fdstr,"%d",pfd[0]); execlp("./cocuk", cocuk",fdstr,null); exit(0); pipe Kullanım Örneği-2 /* cc -o cocuk cocuk.c komutuyla derlenen kız.c */ #include <stdio.h> main(int argc, char *argv[]) int i, fd, nread; char s[80]; fd = atoi(argv[1]); nread = read(fd,s,sizeof(s)); /*gelen mesajı oku*/ printf ("reading %d bytes: %s\n",nread,s); close(pfd[0]); /* ata da okuma ucunu kapa */ boy = getline(msg); /* klavyeden mesajı oku */ write(pfd[1],msg,boy); /* posta kutusuna yaz */ wait(); /* cocuk un sonlanmasını bekle */ 47 48
pipe Komutu UNIX Shell de Pipe Kullanımı Örneği pipe adlı posta kutuları, (shell) komut yorumlama katmanında kullanıcılara, sistem komutlarıyla birlikte kullanılan biçimleriyle yansır. Örnek: ls -l less fork() shell shell exec( ls -l ) ls ls sistem komutu, ürettiği kütük listesini, pipe üzerinden less komutuna aktarır.less komutu bu çıktıyı sayfa sayfa görüntüler. fork() pipe pipe shell exec( less ) less 49 50 UNIX te FIFO UNIX System III den başlayarak named pipe (FIFO) kavramı getirilmiştir. FIFO, aralarında ata-oğul ilişkisi olmayan görevler arasında veri iletişimi ve zamanuyumlama için getirilmiştir. myfifo adlı FIFO kütüğünü yaratmak için aşağıdaki komut kullanılır: mknod( myfifo,s_ififo 0666,0) FIFO kütüğünün adı üzerinde anlaşan görevler open(), read(), write(), close() gibi sistem çağrılarını kullanarak FIFO kütüğüne erişebilirler. FIFO Sunucu Örneği /* fifoserver.c */ #include... #define FIFO_FILE /tmp/myfifo" int main(void) FILE *fp; char readbuf[80]; umask(0); /* Create the FIFO if it does not exist */ mknod(fifo_file, S_IFIFO 0666, 0); while(1) fp = fopen(fifo_file, "r"); fgets(readbuf, 80, fp); printf("received string: %s\n", readbuf); fclose(fp); return(0); 51 52 FIFO İstemci Örneği /* fifoclient.c */ #include... #define FIFO_FILE " /tmp/myfifo" int main(int argc, char *argv[]) FILE *fp; if ( argc!= 2 ) printf("usage: fifoclient [string]\n"); exit(1); if((fp = fopen(fifo_file, "w")) == NULL) perror("fopen"); exit(1); fputs(argv[1], fp); fclose(fp); return(0); 53 Dağıtılmış İşlem (Distributed Processing) Semaforlar gibi alt düzey işleçler, tek işlemcili ya da ortak bir ana belleğe sahip çok işleyicili sistemler üzerinde kullanılabilirler. Ağlar içinde bütünleşmiş bilgisayar sistemlerinin ortak bellekleri yoktur. Semaforlara dayalı zamanuyumlama düzenekleri, farklı bilgisayarlar üstünde çalışan görevler için kullanılamazlar. Tek bir uygulamanın, bir ağ içinde birden fazla bilgisayar sistemini aynı anda kullanabilmesine sağlayan işlem türüne dağıtılmış işlem adı verilir. 54
Uzaktan Yordam Çağırma Alt Düzey veya Üst Düzey Zamanuyumlama? UNIX System V ile birlikte, shared memory, semaphore gibi alt düzey araçlar da posta kutularına alternatif olarak kullanılabilmektedir. Üst düzey araçlar programlama kolaylığı sağlar. Alt düzey araçlar, kullanım kolaylığından ödün vererek daha yüksek performans elde etmeye imkan tanır. Bilgisayar sistemlerindeki uzaktan yordam çağırma (remote procedure call) düzenekleri, dağıtılmış işleme olanak sağlar. send vereceive komutları, dağıtılmış işlem ortamında kullanılabilen tek zamanuyumlama araçlarıdır. 55 56 Monitor Monitor, birlikte çalışan görevlerin, ortak kaynağa erişim yapan yordamlarının (kritik kesimlerinin) toplandığı kümeye verilen addır. Görevlerin monitorda yer alan bir yordamı çağırmaları monitora girmeleri olarak nitelenir. Bir görev monitor içindeki bir yordamın işletimini tümüyle tamamlamadan diğer bir görev monitor içinden yordam çağıramaz. Program derleme aşamasında, monitor biçiminde tanımlanan kesimlerin başına, karşılıklı dışlamayı sağlayacak komutlar derleyici tarafından eklenir. 57 Monitor İçinde Kilitlenme Bir üretici/tüketici görev senaryosunda, üretici görevin monitora girerek, yastık dolu iken buraya yeni bir tutanak eklemeye çalışması durumunda beklemeye alınması gerekir. Aynı şekilde, tüketici görev yastık boşken monitora girip yastıktan bir tutanak okumaya çalışırsa, görevin beklemeye alınması gerekir. Üretici/tüketici görev, gerekli önlemler alınmadan beklemeye alınırsa, hala monitor içinde göründüğünden diğer görevin monitora girmesi engellenir. Bu durumlarda, diğer görevin bekleme durumu son bulamayacağından, kilitlenme olarak bilinen, görevlerin karşılıklı bekleşme durumu ortaya çıkar. 58 wait/signal Komutları Monitor içindeki kilitlenmeleri engellemek için wait ve signal komutları öngörülmüştür. wait(kosul-degiskeni) komutu kendisini çalıştıran görevi koşul değişkenine bağlı bekleme kuyruğuna koyar. signal(kosul-degiskeni) komutu koşul değişkenine bağlı kuyruktaki bir görevi hazır görev durumuna getirir. Monitora girmiş bir görev, wait komutunu çağırdığında, başka görevlerin de monitora girmesine imkan tanımış olur. Monitor Kullanım Örneği - 1 monitor üretici-tüketici tüketici condition dolu,boş; int sayaç; tutanakekle(char *tutanak) if(sayaç == N) wait(dolu); tutanakyaz(tutanak); sayaç++; if(sayaç == 1) signal(boş); tutanakal(char *tutanak) if(sayaç == 0) wait(boş); tutanakoku(tutanak); sayaç--; if(sayaç == (N-1)) signal(dolu); üretici-tüketici tüketici ends 59 60
Monitor Kullanım Örneği 2 char tutanak[80]; kullanıcı() while(true) çıktı-üret(tutanak); üretici-tüketici.tutanakekle(tutanak); char tutanak[80]; yazıcı() while(true) üretici-tüketici.tutanakal(tutanak); dök(tutanak); JAVA da Monitor Kavramı JAVA da bir nesneye erişim yapan yordamların synchronized tanımı, monitor kavramına benzer yaklaşımdır. Paylaşılan nesneyle ilgilisynchronized tanımlı herhangi bir yordamı, en çok bir işletim dizisinin işletmesi sağlanır (karşılıklı dışlama). Bir işletim dizisi, paylaşılan nesneyle ilgilisynchronized tanımlı bir yordamın işletimini tümüyle tamamlamadan, başka bir işletim dizisi aynı nesneye ilişkinsynchronized nitelikli başka bir yordamı işletmeye kalkarsa, otomatik olarak bekler duruma geçer. 61 62 Thread ler Arası Zamanuyumlama için Problemli Bir Java Sınıf Örneği class Counter private int count = 0; public void add(int val) int y = count; y = y + val; count = y; public void sub(int val) int y = count; y = y - val; count = y; 63 Thread ler Arası Zamanuyumlama için Problemli Bir Java Sınıf Örneği Counter sınıfından bir nesne tanımlanır ve eğer birden fazla thread tarafından bu nesne kullanılırsa, thread ler arası zaman uyumlama olmadığı için count değerini güncellemede hatalar oluşabilir. Örneğin birden fazla thread aynı anda add method unu çağırırsa ve ikisi de aynı count değerini okursa günleme hatası oluşur. Bu sorunu düzeltmek için add ve sub method ları syncronized olarak tanımlanmalıdır. Böylece bir thread add method unu çağırdığı zaman, diğer thread ler add veya sub method unu çağırırsa bekleme durumuna alınırlar. 64 Syncronized Java Sınıf Örneği Bariyer (Barrier) Kavramı class SyncronizedCounter private int count = 0; public synchronizedvoid add(int val) int y = count; y = y + val; count = y; public synchronized void sub(int val) int y = count; y = y - val; count = y; 65 Bariyer kullanımı Bir bariyere yaklaşan görevler Biri hariç bloklanan 3 görev Son görev de bariyere ulaşınca, bütün görevler işletime devam ederler. 66
Yemek Yiyen Felsefeciler Problemi (Dining Philosophers) Felsefeci düşünür veya yemek yer. Yemek için 2 çatala ihtiyacı vardır. 2 çatalı aynı anda alamaz. Önce birini sonra ötekini alır. Kilitlenme nasıl oluşabilir? Kilitlenmeyi nasıl önleriz? Yemek Yiyen Felsefeciler Problemi Yanlış bir yaklaşım: 67 68 Görevler Arası Kilitlenme Kilitlenmeyi Oluşturan Koşullar Karşılıklı Dışlama: Bir kaynağın aynı anda yalnız bir görev tarafından kullanılabilmesi. İstem üzerine kaynak atama: Görevin gereksediği kaynakları, teker teker, işletim aşamasında elde etmesi. Kaynak bırakmama: Atanan kaynakların, görevler serbest bırakmadıkça geri alınamaması. Döngüsel Bekleme: Bir görevin elinde tuttuğu kaynaklardan bir ya da daha çoğunun, başka görevlerce de istenmesi. 69 70 Kilitlenmeyi Çözme Yaklaşımları Kilitlenmelere karşı 3 temel yaklaşım: Kilitlenmelerden korunma Kilitlenmelerden sakınma Kilitlenmelerin özdevinimli olarak yakalanması ve ortadan kaldırılması, 71 Kilitlenmelerden Korunma 1. Tüm kaynakları sağlanmadan işlerin görevlerin tanımları yapılmaz. Görevler işletim aşamasında ek kaynak isteminde bulunamazlar. Sorun: Kullanıcılar, işletim aşamasına ilişkin tüm olasılıkları düşünerek kaynak istemleri hakkında abartılı davranabilirler. 2. Görevler, gereksedikleri kaynakları baştan belirler ve kaynakları, sırayla kilit altına almaya çalışırlar. Eğer bir kaynak başka bir görev tarafından kilit altına alınmışsa, o ana kadar kilitlenen kaynak serbest bırakılarak işlemlere yeniden başlanır. Görevin işletimi sonlanmadan bazı kaynakların, örneğin günlenen kütüklerin geri verilmesi mümkün olmayabilir. Veritabanlarında iki aşamalı kilitleme (two phase locking) 72
Kilitlenmelerden Korunma 3. Atanan kaynaklar, görevlerin istemleri dışında da sistemce geri alınabilir. Sorun: Tüm kaynaklar için uygulanması mümkün olmaz. 4. Kaynaklar belirli kümelere ayrılır ve bu kümeler numaralanarak sıralanır. Görevler aynı kümede bulunan kaynaklar için birden çok atama isteminde bulunmazlarsa; (i) ninci kümeden kaynak sağlamış bir görev, yeni bir kaynak istemini yalnızca (i+1), (i+2),..., (i+n) gibi daha üst sıralardaki kümelerden yaparsa; (i) ninci kümedeki kaynaklar, (i-1) inci kümedeki kaynaklardan önce serbest bırakılmak zorunda ise kilitlenme oluşmayacağı kanıtlanabilir. 73 Kilitlenmelerden Korunma (4. Yöntemin devamı) - Sıradüzensel kaynak atama ile kilitlenmelerden korunma: 74 Kilitlenmelerden Sakınma Kilitlenmelerin Yakalanması ve Ortadan Kaldırılması Banker algoritması (Dijsktra 1965) Örnek: Bankerin toplam sermayesinin 10 TL ve ödünç alınan miktarların tablodaki gibi olduğunu varsayın. 3. müşteri 1 TL daha ödünç almak isterse ve banker verirse, banker iflas eder. Görevlerin kaynak istemlerine ilişkin herhangi bir kısıtlamaya gitmeden kilitlenmelerin oluşmasını beklenir Kilitlenme oluştuğunda, nedenleri belirlenerek ortadan kaldırılmaya çalışılır. Kilitlemenin nedenlerini bulmak için, hangi kaynakların hangi görevlere atandığını gösteren, kaynak çizgeleri kullanılır. 75 76 Kilitlenmelerin Yakalanması ve Ortadan Kaldırılması 77