Sunuyu indir
Sunum yükleniyor. Lütfen bekleyiniz
1
İnönü Üniversitesi Bilgisayar Mühendisliği Bölümü
İş Senkronizasyonu İnönü Üniversitesi Bilgisayar Mühendisliği Bölümü
2
Nedir Süreçlerin/ipliklerin faaliyetlerinin paylaşılan veriye erişildiğinde (veri tutarsızlığı vb.) sıkıntı çıkmayacak şekilde koordineli olarak yürütülmesidir. Veri tutarlılığını muhafaza etmek işbirliği yapan süreçlerin düzenli çalıştırılmasını garantileyen mekanizmalar gerektirir.
3
Kritik Bölümler (Tekrar)
X ve Y paylaşılan veriler olsun. İplik 1 Kodu İplik 2 Kodu İplik 3 Kodu X’i Değiştir X’i Değiştir Y’i Değiştir Y’i Değiştir Y’i Değiştir X’i Değiştir
4
Karşılıklı Dışlama (Mutual Exclusion - Mutex)
2 sürecin veya ipliğin kritik bölgede aynı anda olmasına müsaade etmemektedir. Süreçlerin/ipliklerin çalışmalarının rastgele aralıklarla ve oranlarla yapıldığını (preemptive scheduling) varsaymak zorundadır. Zamanlama uygulamanın kontrolünde değildir. Veri senkronizasyonuyla koordinasyon sağlanır. Tutarlılığı sağlamak için talimatların dönüşümlü çalışması sınırlanır. Düşük seviyeli ve yüksek seviyeli mekanizmalarla sağlanır.
5
Karşılıklı Dışlama Sorunu: Aç Kalma
Bir süreci diğer süreçlerin lehine olacak şekilde sürekli erteleme sorunudur. Belirsiz erteleme olarak da bilinir. Genellikle kötü bir zamanlama algoritması neden olur. Bir tür yaşlandırma tekniği geliştirmek çözüm olabilir. Böyle değil!
6
Karşılıklı Dışlama Sorunu: Ölümcül Kilitlenme
İki yada daha fazla sürecin hiçbir zaman olmayacak bir olayı beklemeye kilitlenmeleridir. Genellikle A süreci B’nin iş yapmasını bekler, B de A’ yı bekler. İkisi de beklemede kalakaldıkları için hiçbir iş yapmazlar ve hiçbir zaman bu süreçlere bağlı olaylar oluşmaz. Ayrıca ele alınacaktır.
7
Genel Senkronizasyon Yöntemi
8
Yarış Durumu Örneği Kritik bölüme uyuluyor Uyulmuyor Kritik Bölümler
9
Üretici Tüketici Yarış Durumu
Tamponda 5 nesne olsun. Üreticinin yeni bir nesne üretip tampona koyup miktarı arttırdığı varsayılsın. Tüketicinin de tampondan bir nesne alıp miktarı azalttığı varsayılsın. Üretici Tüketici veya Üretici Tüketici
10
Üretici Tüketici Yarış Durumu
Kritik bölge miktar değerinin değiştirildiği yerdir. Miktar şu şekilde arttırılabilir. (aynı şekilde azaltılabilir) yazmac1 = miktar; //değeri oku yazmac1 += 1; //değeri arttır miktar = yazmac1; //geri yerine yaz
11
Üretici Tüketici Yarış Durumu
O halde Miktar yazmac1 Üretici (miktar++) 5 6 5 4 6 register1 = count register1 = register1 + 1 count = register1 register1 = count register1 = register1 + 1 count = register1 yazmac2 5 4 Tüketici (miktar--) register2 = count register2 = register2 – 1 count = register2 register2 = count register2 = register2 – 1 count = register2 CPU Ana Bellek
12
Hesap Bakiyesi Yarış Durumu
İki müşteriden her biri 100TL çekse de, bakiye 800TL yerine 900TL olur. Bakiye = 1000TL balance = get_balance(account); balance -= amount; Yerel = 900TL İşlemcinin gördüğü çalıştırma dizisi balance = get_balance(account); balance -= amount; put_balance(account, balance); Yerel = 900TL Bakiye = 900TL put_balance(account, balance);
13
Karşılıklı Dışlama Gösterimi
Kritik Bölge Kritik Bölge İplik 1 İplik 2 İplik 1 (hesap bakiyesini değiştir) (hesap bakiyesini değiştir) Kritik Bölge İplik 2 (hesap bakiyesini değiştir) 2. iplik serbestçe girebilir 1. iplik kritik bölgeden ayrılır.
14
POSIX ile Karşılıklı Dışlama
pthread_mutex_lock(&myMutex) .. //kritik bölge detayları pthread_mutex_unlock(&myMutex)
15
Kritik Bölge Şartları Karşılıklı Dışlama: En fazla 1 iplik kritik bölge içinde çalışabilir. İlerleme: Eğer T1 ipliği kritik bölge dışındaysa, T1 ipliği T2 ipliğinin kritik bölgeye girmesine engel olmamalıdır. Aç kalmama: Eğer T1 ipliği kritik bölgeye girmeyi bekliyorsa, eninde sonunda girecektir. İpliklerin kritik bölgeden eninde sonunda çıkacağı kabul edilir. Performans: Kritik bölgeye girme/bölgeden çıkmanın iş yükü bölgede yapılan işe göre küçük olmalıdır.
16
Kilitler Aşağıdaki iki işlem yapan (bellekteki) nesnelerdir.
lock(): Bir iplik kritik bölgeye girmeden önce bunu çağırır, giriş için beklemeyi gerektirebilir. unlock(): Bir iplik kritik bölgeden çıktıktan sonra bunu çağırır, başka bir ipliğin kritik bölgeye girmesini sağlar. Bir lock() çağrısının mutlaka bir unlock() karşılığı olmalıdır. İplik bu iki çağrı arasında kilidi muhafaza eder. Çağıran kilidi tutana kadar lock() dönüş yapmaz. Bir anda en fazla bir iplik bir kilit tutabilir. (istisnalar mevcuttur.)
17
Kilitler int withdraw(account, amount) { lock(kilitdegiskeni);
balance = get_balance(account); balance -= amount; put_balance(account, balance); unlock(kilitdegiskeni); return balance; } Kritik bölge
18
Dönen Kilitler (Spinlocks)
Oldukça basit bir kilit implementasyonudur. lock() ve unlock() atomik olmalıdır. («ya yep ya hiç» çalıştırma mantığı) struct lock_type { int held = 0; } lockvar; void lock(lockvar) { while (lockvar->held); lockvar->held = 1; } void unlock(lockvar) { lockvar->held = 0; Çağıran kilidin bırakılmasını meşgulde bekler.
19
Karşılıklı Dışlama İçin Donanım Desteği
Çoğu sistem kritik bölge kodunu yazmak için donanım desteği sağlamaktadır. Sonraki slaytlardaki çözümlerin hepsi kilitleme (kritik bölgeleri korumak için) fikrine dayanır. Tek işlemcilerde kesmeler kapatılabilir. Mevcut çalışan kod öncelik kullanılmaksızın çalışacaktır. Bu yöntem çok işlemcili sistemlerde genellikle çok verimsizdir. Modern makineler özel atomik (kesilemeyen) donanım talimatları sağlamaktadır. Bunlar bellekteki veriyi (memory word) test eden ve değerini atayan talimat ile iki bellek içeriğini takas eden talimatlardır.
20
test_and_set Talimatı
boolean test_and_set (boolean *hedef) { boolean rv = *hedef; *hedef = TRUE; return rv: } Atomik olarak çalıştırılır. Geçilen parametrenin orijinal değerini döner. Geçilen parametrenin yeni değerini “TRUE” olarak ayarlar.
21
test_and_set() Kullanarak Çözüm
lock paylaşımlı Bool değişkenine FALSE atanmıştır. do { while (test_and_set(&lock)) ; /* hiçbir şey yapma */ /* kritik bölge */ lock = false; /* kalan bölge */ } while (true);
22
compare_and_swap Talimatı
int compare _and_swap(int *value, int expected, int new_value) { int temp = *value; if (*value == expected) *value = new_value; return temp; } Atomik olarak çalıştırılır. Verilen “value” parametresinin orijinal değerini döner. Sadece “value” ==“expected” olursa ”value” değişkenine verilen “new_value” parametresinin değerini atar. Yani takas ancak bu şartla gerçekleşir.
23
compare_and_swap Kullanarak Çözüm
Paylaşımlı tamsayı “lock” 0 ilk değerini alır. do { while (compare_and_swap(&lock, 0, 1) != 0) ; /* hiçbir şey yapma */ /* kritik bölge */ lock = 0; /* kalan bölge */ } while (true);
24
test_and_set ile Bağlı Bekleyen Karşılıklı Dışlama
do { waiting[i] = true; key = true; while (waiting[i] && key) key = test_and_set(&lock); waiting[i] = false; /* kritik bölge */ j = (i + 1) % n; while ((j != i) && !waiting[j]) j = (j + 1) % n; if (j == i) lock = false; else waiting[j] = false; /* kalan bölge */ } while (true);
25
Dönen Kilitlerdeki Sıkıntı
Aşırı israfa neden olur! İplikler CPU üzerinde kilit dönüşünü bekler. Bol miktarda CPU zamanı yiyecek ve diğer ipliklerin işini yavaşlatacaktır. Kilitlemeye çalışan bir sürü iplik varsa ne olur? Dönen kilitleri yüksek seviye senkronizasyon yapıları için temel bileşen olarak kullanmak daha mantıklıdır. İplik 0 İplik 1 İplik 2 İplik 3 İplik 4 İplik 5 Süreçler/ İplikler Kritik Bölge Kilitli ve döner Kilitli ve döner Kilitli ve döner Kilitli ve döner Kilitli ve döner İplik tarafından kendi kritik bölgesinde kullanılabilecek CPU zamanını israf etmektedir.
26
Peterson’un Çözümü Yazılım tarafında bir çözümdür, donanım veya çekirdekle işi yoktur. Peterson.enter //pthread_mutex_lock(&myMutex) gibidir .. //kritik bölge detayları Peterson.exit //pthread_mutex_unlock(&myMutex) gibidir Sadece 2 süreç/iplik için çalışır. Bu çözüm işe yarar mı? lock = 1 (global değişken) Kritik bölgeye girmek isteyen bir iplik lock değerine bakar. (lock == 1) Doğruysa girer ve değeri azaltır. (lock--) Değilse, başka bir iplik azalttığı için girmez. İşe yaramaz zira lock da bir paylaşımlı global değişkendir. Başka koruma olmadan sadece bir değişken yetmez.
27
Peterson’un Çözümü LOAD ve STORE makine talimatlarının atomik olduğunu varsayalım. İki süreç iki değişken paylaşır: int turn; boolean flag[2]; turn değişkeni kimin kritik bölgeye girme sırasının geldiğini gösterir. turn = i, Pi sürecinin çalışabileceğini gösterir (i=0,1). flag dizisi bir sürecin kritik bölgeye girmeye hazır olup olmadığını gösterir. flag[i] = true, Pi sürecinin hazır olduğunu belirtir. (girmek istiyor)
28
Peterson’un Çözümü Pi için algoritma: (Pj diğer süreç)
Girmek için hazır Diğer sürece sırayı devrediyor Meşgulde bekliyor
29
Peterson’un Çözümü flag[] turn Paylaşılan Değişkenler:
SÜREÇ i (0) SÜREÇ j (1) do { flag[j] = TRUE; turn = i; while (flag[i] && turn == i); kritik bölge.. flag[j] = FALSE; kalan bölge.. } while (1) do { flag[i] = TRUE; turn = j; while (flag[j] && turn == j); kritik bölge.. flag[i] = FALSE; kalan bölge.. } while (1) flag[] turn Paylaşılan Değişkenler: i=0, j=1 yereldir.
30
Önceliğin Ters Yüz Olması (Priority Inversion)
Düşük öncelikli bir sürecin kilitlediği kaynak nedeniyle yüksek öncelikli bir sürecin ihtiyaç duyduğu halde bu kaynağa erişememesi açmazıdır. Öncelik Kalıtımı: Yüksek öncelikli sürecin önceliği geçici olarak düşük öncelikli sürece verilir. Dolayısıyla orta öncelikli süreçler düşük öncelikli sürecin işi bitene kadar araya giremezler. Kaynak serbest kalınca, düşük öncelikli süreç başlangıçtaki öncelik seviyesine geri döner. Rastgele Yükseltme: Kilit tutan süreçler kritik bölgeden çıkana kadar öncelik değerleri rastgele yükseltilir. Windows görev yöneticisi bu mekanizmayı kullanır.
31
Ara Konu: C Kodu İçinde Assembly
__asm__ {}; bloklarıyla istediğiniz makine dili kodunu yazabilirsiniz.
32
Ara Konu: Petri Netler 1962’ de Carl Adam Petri tarafından kimyasal işlemlerin modellenmesi için geliştirilmiştir. UML aktivite diyagramları gibi seçim, iterasyon ve koşut zamanlı çalıştırma içeren adımsal süreçler için bir grafiksel notasyon sağlar. Ayrıca çalışma semantiği için matematiksel tanımı ve süreç analizi için iyi geliştirilmiş bir matematik teorisi de bulunmaktadır.
33
Ara Konu: Petri Netler 4 temel bileşen içerir.
Daireler durumları gösterir. Kutular gerçekleşmesi gereken aktivite ve koşulları da belirten bir durumdan diğerine geçişlerdir. Yönlü ve ağırlıklı oklar durumlar ve geçişler arasındadır. Bir aktivite, koşulun gerçekleşmesi için ona işaret eden durumlarda jeton bulunması gerekir. Jeton geçişin tetiklenmesini sağlar. Ok ağırlıkları durumu oluşturan jeton sayısını belirtir. Geçişin tetiklenmesi için bütün girişlerden gerekli sayıda jetona ihtiyaç vardır. Jetonlar bu sayede bir sonraki duruma aktarılır. Bir geçişle birden fazla duruma gidildiğinde jetonlar çoklanır.
34
Bloklayan Kilitler (Mutex Locks)
Kritik bölgeye girmek isteyen bir ipliği bloklar, ipliği uyku moduna gönderir. Böylece diğer ipliklerin çalışması için CPU serbest kalır.
35
Yüksek Seviye Senkronizasyon İhtiyacı
Kilitler senkronizasyon için kullanılan temel bir bileşendir. Kilitler pek çok iş için kullanılmakla birlikte programların bazen farklı ihtiyaçları olmaktadır. Örneğin herhangi bir sayıda ipliğin okuyabildiği ama sadece bir ipliğin yazabildiği bir paylaşımlı değişken olsun. Bu koddaki sıkıntı nedir? Okuyan() { lock(lockvar); mycopy = shared_var; unlock(lockvar); return mycopy; } Yazan() { lock(lockvar); shared_var = NEW_VALUE; unlock(lockvar); }
36
Semaforlar (Semaphores)
İlk değeri atanmış, paylaşımlı sayaçlardır. Edsger Dijkstra tarafından 1960’larda tasarlanmıştır. Semaforlar için iki atomik işlem tanımlıdır: P() veya down() veya wait() Felemenkçe «proeberen» (test) Semafor değerinin sıfırdan büyük olmasını bekler sonra azaltır. V() veya up() veya post() veya signal() Felemenkçe «verhogen» (arttır) Semafor değerini 1 arttırır.
37
1 Değeri Atanmış Semafor
38
İplik 1 wait() Çağırır ve Devam Eder
Thread 1 wait() Semafor Semafor değeri önce: 1 Semafor değeri sonra: 0
39
İplik 2 wait() Çağırır ve Bloklar
Thread 2 wait() Z z Semafor Semafor değeri önce: 0 Semafor değeri sonra: -1
40
İplik 3 signal() Çağırır
Thread 3 signal() Z z Thread 2 wait() Semafor Semafor değeri önce: -1 Semafor değeri sonra: 0
41
İplik 4 signal() Çağırır ve Devam Eder
Thread 4 signal() Semafor Semafor değeri önce: 0 Semafor değeri sonra: 1
42
C Semafor İşlemleri Pthreads fonksiyonları:
#include <semaphore.h> int sem_init(sem_t *s, 0, unsigned int val);} /* s = val */ int sem_wait(sem_t *s); /* P(s), down(s) */ int sem_post(sem_t *s); /* V(s), up(s), signal(s)*/
43
Semaforlar Niye Kullanışlıdır
İkili semafor aslında bir kilittir. Semafor; değeri 0 veya 1’ de başka bir değer olarak ayarlanabildiğinde anlamlı olur. Kaynak tahsisi gibi senkronizasyon problemlerinde semafor değerini eldeki kaynak miktarı olarak atayıp kullanabilirsiniz.
44
Semaforların Çözemedikleri
Semaforların gücünün çoğu eşleşmeyen wait() ve signal() çağrılarından türemektedir. Kilitlerdeki lock() ve unlock() eşleşme zorunluluğu yoktur. Bu nedenle semaforla sıkıntı yaşamak daha kolaydır. Senkronizasyon için daha temiz ve iyi tanımlı bir yapı (dil desteği) gerekmektedir.
45
Monitörler İşletim sistemi dışında programlama dilinden de yardım almaktır. Süreç/iplik senkronizasyonu için yüksek seviye soyutlamadır. Java desteklemektedir, C ise ancak semafor çeşitlemesi yapabilir. Derleyici kodunuzun kritik bölgelerinin korunmasını garantiye alır. Kodun kritik bölgesi belirtilir, monitör içine alınır ve derleyici koruma kodunu yerleştirir. Semafor kullanarak monitör implementasyonu derleyici yazarı/dil geliştiricisinin derdidir, uygulama geliştiricisi işine bakar.
46
Paylaşılan veriye erişen
18/02/08 Monitörler Paylaşılan Veri Paylaşılan veriye erişen metodlar kilitlenmemiş
47
Paylaşılan veriye erişen
18/02/08 Monitörler Paylaşılan Veri Paylaşılan veriye erişen metodlar kilitli zzzz... Uyuyan iplik artık monitörün içinde değildir. Bekleme kuyruğunda da değildir.
48
Paylaşılan veriye erişen
18/02/08 Monitörler Paylaşılan Veri Paylaşılan veriye erişen metodlar kilitli Monitör kilitli kalır! (Farklı bir iplik kilidin sahibidir.) zzzz... notify()
49
Paylaşılan veriye erişen
18/02/08 Monitörler Paylaşılan Veri Paylaşılan veriye erişen metodlar kilitli notify()
50
Paylaşılan veriye erişen
18/02/08 Monitörler kilitli Paylaşılan Veri Paylaşılan veriye erişen metodlar İpliklerin monitöre hangi sırada geldiklerinin hiçbir garantisi yoktur. (FIFO olmak zorunda değildir!)
51
Java’da Monitörler Her Java nesnesinde bir kilit ve durum değişkeni vardır. Bunlar için ayrıca sınıf tanımları yoktur. Her nesne bir monitördür/nesnenin bir monitörü vardır Bir nesnenin monitörünün içinde en fazla bir iplik olabilir. Bir iplik bir nesnenin monitörüne “synchronized” tanımlanmış bir metot çalıştırarak girer. Aynı sınıfta “synchronized” veya diğer metotlar karışık kullanılabilir. Her nesneye durum değişkeni olarak davranılabilir. wait() : Mevcut ipliği askıya alır. notify() : Bekleme listesinden rastgele bir ipliğe (T) bildirim gönderir. T hedef nesne için (en azından notify çağrısı yapan iplik kilidi serbest bırakana kadar daima bloklamasını sağlayan) senkronizasyon kilidini tekrar elde etmelidir. Eğer başka bir iplik kilidi önce elde ederse bloklamaya devam edecektir. notifyAll() : Askıdaki ipliklerin hepsine bildirim gönderir.
52
Java’da Monitör Örneği
18/02/08 Java’da Monitör Örneği class Sayac { private int miktar = 0; public void synchronized arttir() int n = miktar; miktar = n+1; } Sayac c, d; /* Paylaşılan nesneler */ İplik A İplik B … c.arttir(); … c.arttir(); İplik A arttir()çalıştırırken İplik B arttir()çağırdığında, İplik B monitörden çıkana kadar bloklanacaktır. «synchronized» bir metot kritik bölge demek değildir! Senkronizasyon kodun kendisiyle (sınıf tanımı) değil nesne oluşumlarıyla (object instance) ilişkilidir. Dolayısıyla c.arttir(), d.arttir() ile aynı anda çalıştırılabilir.
53
Durum Değişkenleri (Condition Variables)
Kavramsal olarak bir durum değişkeni bir ipliğin bazı ifadelerin doğru olana kadar beklemesi üzerine monitörle ilişkili bir iplik kuyruğudur. İplikler durum değişkenlerini; bazı şartlar sağlanana kadar beklerken ayrıcalıklı erişimden geçici olarak vazgeçmek için, tekrar ayrıcalıklı erişim elde etmeden ve işlerine devam etmeden önce, koşulların sağlandığını diğer ipliklere sinyal geçmek için kullanabilirler.
54
Pthreads Senkronizasyonu
Pthreads API İ.S bağımsızdır. Mutex kilitleri ve durum değişkenleri sağlar. Bazı eklentileri okuma-yazma kilitleri ve dönen kilitler de içerir.
55
Linux Senkronizasyonu
2.6 çekirdek sürümü öncesinde Linux kısa kritik bölgeleri oluşturmak için kesmeleri iptal ediyordu. 2.6 ve sonrasında tamamen öncelik kullanımlı yapılmaktadır. Linux semaforlar, atomik tam sayılar, dönen kilitler ve bunların okur- yazar çeşitlerini sağlamaktadır. Tek işlemcili sistemde dönen kilitlerin yerine çekirdek öncelik kullanımını açma/kapama kullanılır.
56
Solaris Senkronizasyonu
Çok işlevlik, çok iplikli çalışma ve çok işlemcililik desteği için çeşitli kilitler tanımlamaktadır. Verim için veriyi kısa kod parçalarından koruyan uyarlanabilir mutex yapıları kullanır. Durum değişkenleri, veriye erişmesi gereken uzun kod bölümleri için okur-yazar kilitler ve uyarlanabilir mutex veya okuma-yazma kilidi elde etmeyi bekleyen ipliklerin listesini sıralayan turnikeler kullanır. Öncelik kalıtımı turnikedeki çalışan bir ipliğe kendi turnikesindeki iplikler arasında en yüksek önceliği verir.
57
Windows Senkronizasyonu
Tek işlemcili sistemlerde global kaynaklara erişimi korumak için kesme maskeleri kullanır. Çok işlemcili sistemlerde dönen kilitler kullanır. Dönen kilitli iplik öncelik kullanımına maruz bırakılmaz. Ayrıca kullanıcı tarafında mutex, semafor, olay ve sayaç (timer) olarak davranabilen sevkedici nesneler sağlar. Olaylar durum değişkeni gibi davranırlar. Sayaçlar zaman dolduğunda bir veya daha fazla ipliğe bildirim yapar. Sevkedici nesneler ya sinyalli durumda (nesne müsait) veya sinyalsiz durumda (iplik bloklanacak) olurlar.
58
Üretici Tüketici Problemi Java’da Bir Çözüm
class Buffer { private char [] buffer; private int count = 0, in = 0, out = 0; Buffer(int size) { buffer = new char[size]; } public synchronized void insert(char c) { while(count == buffer.length) { try { wait(); } catch (InterruptedException e) { } finally { } System.out.println("Producing " + c + " ..."); buffer[in] = c; in = (in + 1) % buffer.length; count++; notify(); public synchronized char remove() { while (count == 0) { char c = buffer[out]; out = (out + 1) % buffer.length; count--; System.out.println("Consuming " + c + " ..."); return c;
59
Yemek Yiyen Düşünürler Problemi
Bir düşünür (süreç) yemek için iki çatala (kaynaklar) ihtiyaç duymaktadır. Bir düşünür çatalı eline aldığı sürece komşuları çatala dokunamaz.
60
Yemek Yiyen Düşünürler Problemi
Bir düşünür (süreç) yemek için iki çatala (kaynaklar) ihtiyaç duymaktadır. Bir düşünür çatalı eline aldığı sürece komşuları çatala dokunamaz. (karşılıklı dışlama)
61
Yemek Yiyen Düşünürler Problemi
Bir düşünür (süreç) yemek için iki çatala (kaynaklar) ihtiyaç duymaktadır. Bir düşünür çatalı eline aldığı sürece komşuları çatala dokunamaz.
62
Yemek Yiyen Düşünürler Problemi
Düşünür 2 durumdadır: Yiyor (çatal gerekir) ve düşünüyor (çatal gerekmez). Paralellik istenmektedir, mesela 3 veya 4, 1 yiyorken de yiyebilmelidir. (0 ve 2 değil) Ölümcül kilitlenme olmamalı, yani her biri diğerini belirsiz bir süre boyunca beklememelidir. Düşünürlerin aşırı beklemekten aç kalmaları ve vefat etmeleri de istenmemektedir. Amaç düşünürlerin yeme-düşünme döngüsünü sağlamaktır.
63
Yemek Yiyen Düşünürler Problemi İlk Deneme
Koşut zamanlı ancak kilitlenme önlemeyen bir semafor çözümü Semaphore forks[5]; //ilk değer 1 (masada 5 düşünür varsayıyoruz) do { wait( forks[i] ); wait( forks[ (i + 1) % 5] ); // ye signal( forks[i] ); signal( forks[ (i + 1) % 5] ); // düşün } while(TRUE); Soru: Ölümcül kilitlenme mümkün müdür?
64
Yemek Yiyen Düşünürler Problemi
Elbette mümkündür zira: 4 sol çatalı alır. Ara geçiş 3 sol çatalı alır. Ara geçiş, … 0 sol çatalı alır. Ara geçiş. 4 (0’ın tuttuğu) sağ çatalı almak ister. Geçişlerin bu şekilde olması muhtemel olmasa da mümkündür. Kilitlenme tehlikesi olmaksızın bir çözümü yine semaforlar vermektedir. Eğer sağ çatalı alamıyorsan solu yerine bırak. Her iki çatalı da bir anda al. (atomik olarak)
65
Okur Yazar Problemi Bir veri kümesi okur (verileri sadece okuyabilir) ve yazar (verileri okuyabilir ve değiştirebilir) türünden koşut zamanlı süreçler arasında paylaşılmaktadır. Çok sayıda okurun aynı anda okumasına ve bir anda sadece bir yazarın değiştirmesine müsaade etmek nasıl mümkündür? Paylaşılan veriler Veri kümesi İlk değeri 1 olarak atanmış rw_mutex semaforu İlk değeri 1 olarak atanmış mutex semaforu İlk değeri 0 olarak atanmış read_count tam sayı değişkeni Çevrimiçi otobüs, uçak rezervasyonu, çok iplikli ön bellekli Web proxy
66
Okur Yazar Problemi Okur Sürecin Yapısı Yazar Sürecin Yapısı
do { wait(mutex); read_count++; if (read_count == 1) wait(rw_mutex); signal(mutex); /* okuma gerçekleşir */ ... wait(mutex); read count--; if (read_count == 0) signal(rw_mutex); } while (true); do { wait(rw_mutex); /* yazma gerçekleşir */ ... signal(rw_mutex); } while (true); Bir okur sadece, bir yazarın yazmayı tamamlamasını beklemelidir. Bir okur diğer okurların okumayı tamamlamalarını beklememelidir. Bir yazar diğer yazarların yazmayı bitirmelerini beklemelidir. Bir yazar bütün okurların okumayı bitirmelerini beklemelidir.
67
Değerlendirme signal(semafor) asla bloklamaz, her zaman ilerletir.
wait(semafor) bloklayabilir; eğer semaforun mevcut değeri 0 ise bloklayacak, 0’ dan büyükse azalttıktan sonra ilerleyecektir. Semafor değerine doğrudan erişilemez, if(semafor == i) türünden mukayeselere müsaade edilmemektedir.
68
Okur Yazar Problemi Çeşitleri
Yazar paylaşılan nesneyi kullanma yetkisini alana kadar hiçbir okur bekletilmez. Yazar müsait olunca mümkün olan en kısa zamanda yazmayı gerçekleştirir. İki çeşit de farklı çeşitlemelere götüren açlık durumları içerebilir. Bazı sistemlerde bu problem çekirdek tarafından sağlanan okur-yazar kilitleriyle çözülmektedir.
69
Sigara İçenler Problemi
Sigara içmek için tütün, kağıt ve kibrite (kaynaklar) ihtiyaç vardır. Üç sigara içicinin (süreçler) her birinde sırayla sınırsız tütün, kağıt ve kibrit vardır. Dördüncü biri (İ.S.) masaya rastgele iki tür malzeme koyar. İçicilerden biri malzemeleri alarak sigarasını yakar. Sistemi kilitlenme olmadan senkronize ediniz. Ek kısıtlar: Dördüncü kişi kodu değiştirilemez. Çözümde koşullu ifadeler (if) kullanılamaz. Bu kısıtlar semaforla çözümü imkansız kılar. YASAL UYARI: SİGARA SAĞLIĞA ZARARLIDIR!
70
Sigara İçenler Problemi Çözümü
Dördüncü kişi: Malzemeleri alacak içiciyi uyandırır ve uykuya geçer. İçici sigarayı içerken dördüncüyü uyandırır. lock 1, diğer semaforlar 0 ilk değerlidir. 1 while(1) { 2 P( lock ); //Semaforu indir 3 randNum = rand(1,3); // 1-3 arası rastgele sayı seç 4 if ( randNum == 1 ) { 5 // Masaya tütün koy 6 // Masaya kağıt koy 7 V( smoker_match ); // Kibritli içiciyi uyandır 8 } else if ( randNum == 2 ) { 9 // Masaya tütün koy 10 // Masaya kibrit koy 11 V( smoker_paper ); // Kağıtlı içiciyi uyandır 12 } else { 13 // Masaya kibrit koy 14 // Masaya kağıt koy 15 V( smoker_tobacco ); } // Tütünlü içiciyi uyandır 16 V( lock ); //Semaforu kaldır 17 P( agent ); // Dördüncü uykuya geçer 18 } İçici sigarasını içerken dördüncü yeniden malzemeler koyar ve alakalı içiciyi uyandırır. Tütün sahibi içici (diğerlerine de uyarlanabilir) 1 while(1) { 2 P( smoker_tobacco ); // Uykuya geç 3 P( lock ); 4 // Kibriti al 5 // Kağıdı al 6 V( agent ); 7 V( lock ); 8 /* Sigarayı iç ve uyu */ } İçici, istediği malzemeleri almak için dördüncü tekrar uyandırana kadar uyur. YASAL UYARI: SİGARA SAĞLIĞA ZARARLIDIR!
71
Uyuyan Berber Problemi
Bir berber dükkanında N sandalyeli bekleme odası ve berberin oturduğu berber odası vardır. Eğer müşteri yoksa berber uyur. Eğer bütün sandalyeler doluyken dükkana müşteri gelirse, müşteri geri gider. Berber meşgulse ama oturacak yer varsa gelen müşteri boş bir yere oturur. Berber uyuyorsa gelen müşteri berberi uyandırır.
72
Uyuyan Berber Problemi Semafor Şablonu
semaphore customer; init(customer,0); // hizmet bekleyen müşteri sayısı semaphore barber; init(barber,0); // müşteri bekleyen berber sayısı semaphore mutex; init(mutex,1); // karşılıklı dışlama için int waiting = 0; //sandalyelerde oturan müşteriler void barberThread(){ while (1) { ………………. cutHair(); ……………. } void customerThread(){ ……………….. getHairCut(); // bütün sandalyeler doluysa çalıştırılmayabilir ………………
73
Uyuyan Berber Problemi Monitör Şablonu
monitor BarberShop{ condition waitingForCustomers, waitingForBarbers; int waiting = 0; // sandalyede bekleyen müşteri sayısı void barber(){ …………………. cutHair(); ………………. } void customer(){ getHairCut(); // bütün sandalyeler doluysa çalıştırılmayabilir ……………… void barberThread(){ while(1) BarberShop.barber(); void customerThread(){ BarberShop.customer();
74
Uyuyan Berber Problemi
B: Müşteri yokken berber uyuyor mu? BM: İlk müşteri berberi uyandırıp saçını kestiriyor mu? BMM: İkinci müşteri berberin ilk müşterinin tıraşını bitirmesini bekliyor mu? BMMMMMMM: 7. müşteri tıraşını olmadan ayrılır mı? BMMMMM: Berber ilk müşterinin tıraşını bitirdikten sonra bekleyen bir müşteriyi uyandırıyor mu? Son olarak bu çözüm verimli midir? İhtiyaç duyulandan fazla bildirim sinyali gönderme veya daha fazla değişken kullanma iyi bir uygulama değildir.
75
18/02/08 Büyük Resim.jpg Esas mesele senkronizasyonun doğru biçimde yapılmasının zor olmasıdır. Kilitler, semaforlar, durum değişkenleri, monitörlerden hangisini seçmeli? Kilitler çoğu durum için oldukça basittir. Sıkıntı: En verimli çözüm olmamasıdır. Mesela standart bir kilitin içinde çok okuyan fakat bir yazana müsaade edilemez. Durum değişkenleri ipliklerin bir kilidi tutarken uyumalarını sağlar. Mesa ve Hoare semantiğinden hangisini kullandıklarını anladığınızdan emin olunuz. Semaforlar genel işlevsellik sağlar. Fakat aynı zamanda işleri berbat etmek de çok kolaydır.
Benzer bir sunumlar
© 2024 SlidePlayer.biz.tr Inc.
All rights reserved.