İşletim Sistemleri (Operating Systems)
PROCESS SENKRONİZASYONU (PROCESS SYNCHRONIZATION)
Kritik Bölge Probleminin Olası Çözümleri Donanıma Dayalı Çözümler
Donanıma Dayalı Çözümler Yazılım tabanlı kritik bölge problemi çözümlerinin (Peterson’un algoritması gibi) modern bilgisayar mimarilerinde çalışmasının garantisi yoktur. Özellikle kritik bölge probleminin çözümünde, karşılıklı dışlama kapsamında yazılımsal yaklaşımlarda process’ler, kaynağın serbest olup olmadığını sürekli olarak sınamak suretiyle CPU’yu gereksiz yere meşgul ediyorlardı.
Donanıma Dayalı Çözümler Dekker ve Peterson'un algoritmaları, N process için genelleştirilebilir. Fakat, N sabitlenmiş ve önceden bilinmelidir. Aynı zamanda, bu algoritmalar çok karmaşıktır ve karşılıklı dışlama mekanizmasının uygulanması zordur! Bu yüzden kritik bölge problemini donanım temelli çözmek için bazı yöntemler geliştirilmiştir.
Donanıma Dayalı Çözümler Kritik bölge probleminin çözümü için İki tür donanıma dayalı senkronizasyon metodu vardır: Kesmeleri kapatmak/açmak (Disabling/Enabling interrupts) : Bu metod, çok işlemcili sistemlerde yavaş ve uygulanması zor. Özel ayrıcalıklı makine komutları kullanmak : Test and set (TS) Swap Compare and Swap (CS)
Kesmeleri kapatmak/açmak (Disabling/Enabling interrupts) Donanım temelli çözüm yöntemlerinden ilk akla gelen, kesmelerin(interrupt) kritik bölge işleminde kapatılmasıdır. Tek işlemcili sistemlerde, kritik bölge problemi paylaşılan veriler üzerinde process’lerin kesme almadan gerçekleştirilmesiyle çözümlenebilir. Böylece paylaşılan veriler üzerinde işlem yapılırken, başka bir değişikliğin yapılması söz konusu olmayacaktır. Ancak bu yöntemin de bazı sakıncaları vardır.
Kesmeleri kapatmak/açmak (Disabling/Enabling interrupts) Kesmeler devre dışı bırakıldığından, process kritik bölgede yürütülürken hiçbir bağlam anahtarlama (contex switching) oluşmaz. Kesmelere dayanan bazı özellikler (örneğin clock) düzgün çalışmayabilir.
Kesmeleri kapatmak/açmak (Disabling/Enabling interrupts) Normal durumda process kesilene veya sistem çağrısı yapana kadar çalışmaya devam eder. – Kritik bölge yürütümünde kesmeleri kapatarak karşılıklı dışlama sağlamış olur. – Ancak bu yöntem işlemcinin birden fazla process’i zaman paylaşımlı olarak çalıştırma özelliğine aykırı bir durumdur.
Kesmeleri kapatmak/açmak (Disabling/Enabling interrupts) Bu yöntem tek işlemcili sistemlerde çalışır, çok işlemcili sistemlerde uygun çözüm değildir. İşlemciler bağımsız davranırlar. İşlemciler arasında kesme mekanizması yoktur. Çok işlemcili sistemlerde, kesmelerin disable/enable yapılması için tüm işlemcilere mesaj göndermek için zaman gereklidir ve sistem performansı düşer.
Özel Makine Komutlarına Dayalı Çözümler (Special Machine Instructions) Kritik bölge problemi için özel makine komutlarına dayalı çözümler, temel olarak kilitleme (locking) tabanlı yaklaşımlardır. Process kritik bölgeye girmeden önce kilit kullanır, kritik bölgeden çıkarken de kilidi açılır. Günümüzde modern işlemciler, kilidi uygulamak için kullanılabilecek özel atomik donanım komutları sağlar.
Özel Makine Komutlarına Dayalı Çözümler Atomik (non-interruptible) komutlar : Tek bir komut çevriminde gerçekleşen komutlardır, kesilemezler. Böyle bir komut yürütüldüğünde, CPU’lar tarafından çeşitli aşamalarla yürütülen diğer tüm komutlar bu komut tamamlanıncaya kadar durdurulacaktır. Bu nedenle, iki farklı komut aynı anda verilirse, farklı CPU'larda olsalar da sırayla çalıştırılacaktır. Ayrıcalıklı (Privileged): Bu komutlar genel olarak ayrıcalıklıdır, yani sadece supervisor veya kernel modunda çalışabilirler.
Özel Makine Komutlarına Dayalı Çözümler Çoğu modern bilgisayar sistemi, bir word’ü test etmeyi/güncellemeyi veya iki word’ü yer değiştirmeyi sağlayan özel donanım komutları sağlar. bir word içeriğini test edip değiştirme, (test and set lock -TS) test et ve değiştir komutu -TestAndSet() iki word içeriğini yer değiştirme, (swap lock) yer değiştir komutu – Swap() bir word içeriğini karşılaştırıp değiştirme, (compare and swap lock -CS) karşılaştır ve yer değiştir komutu - CompareAndSwap()
Özel Makine Komutlarına Dayalı Çözümler Kilitleri Kullanarak Kritik Bölge Problemine Çözüm Kilit çözümünün genel düzeni şöyledir: do { acquire lock critical section release lock remainder section } while (TRUE); Kritik kod bölgesinin mümkün olduğunca küçük olması, yalnızca paylaşılan verilere erişen/değiştiren bölümleri kilitlemesi gerekir.
Test and Set Komutunu Kilitleme için Kullanma Bir çok bilgisayar; özellikle birden fazla işlemcili olanlar, Test and Set Lock (TS) komutuna sahiptir. lock önekini alan bir komutun işletimi sırasında, bu komutu işleten işlemcinin bellek erişim döngüsünün bölünmesine izin verilmez. Yani bu komut kesilemez.
Test and Set Komutunu Kilitleme için Kullanma Shared data: boolean lock = FALSE; Process Pi do { while (TestAndSet(&lock)); critical section lock = FALSE; remainder section } while (TRUE);
Test and Set Komutunu Kilitleme için Kullanma lock değişkeni bellek alanında saklanır. lock = {TRUE , FALSE} Test and Set Lock (TS) komutu ile bellekteki lock değeri önce test edilir dönüş değeri FALSE olduğunda kilit ele geçirilir. Bellekteki lock değişkeni TRUE ile değiştirilir. Process kendi kritik bölgesine girer ve işlemlerini tamamladıktan sonra tekrar lock değişkeninin değerini FALSE olarak değiştirir.
Test and Set Komutunu Kilitleme için Kullanma Eğer lock değeri test edildiğinde TRUE ise, bir başka process zaten kilidi ele geçirmiştir. (ve hala ona sahiptir) lock değişkenin bellekten okunup, alınması ve değerinin değiştirilmesi tek hamlede gerçekleştirilen bir işlemdir. Diğer işlemciler de bu süreçte bu değişkene ulaşamazlar. TS komutunu kullanan işlemciler belleğe giden veri yollarını kilitleyerek diğer işlemcilerin belleğe ulaşımını engeller.
Test and Set Komutunu Kilitleme için Kullanma
Test and Set Komutunu Kilitleme için Kullanma
Test and Set Komutunu Kilitleme için Kullanma Bir kilit sisteme iade edildiğinde ve diğer process’ler kilit üzerinde harekete geçmek için beklerken yalnızca bir process’in FALSE ile döneceğinden emin olunmalıdır. Bu metod ile karşılıklı dışlama (mutual exclusion) ve ilerleme (progress) sağlansa bile sınırlı bekleme (bounded waiting) gerçekleştirilemeyebilir.
Swap Komutunu Kilitleme için Kullanma Swap komutu da kesilemeyen özel donanım komutudur. lock ve key adı verilen iki değişkeni kullanır. İlk değeri FALSE olan global bir lock değişkeni ve her process için lokal bir key değişkeni tanımlanır. lock FALSE ise, bir process kritik bölgesine girebilir, aksi takdirde giremez. Bellekteki lock değeri, key değerine eşit olmadığı sürece değiştirilmez.
Swap Komutunu Kilitleme için Kullanma Shared data: boolean lock = FALSE; Process Pi do { /* Each process has a local Boolean variable key */ key = TRUE; while (key == TRUE) Swap(&lock, &key); critical section lock = FALSE; remainder section } while (TRUE);
Swap Komutunu Kilitleme için Kullanma Swap komutu da, karşılıklı dışlama (mutual exclusion) ve ilerlemeyi (progress) sağlarken, yarış durumunun (race condition) önlenmesi için gerekli sınırlı bekleme (bounded waiting) şartını sağlamamaktadır.
‘Compare and Swap’ Komutunu Kilitleme için Kullanma compare and swap komutu (CS), test and set (TS) komutuna benzerdir, ancak daha karmaşıktır. CS komutu üç parametre alır: belirli bir değer, bellek konumundaki "beklenen değer" ve belirli bir yeni değer. Paylaşılan değişken: global bir lock değişkeni başlangıçta 0 yapılır. compare and swap, bir bellek konumunun içeriğini belirli bir değerle atomik olarak karşılaştırır ve yalnızca aynı oldukları zaman, bu bellek konumunun içeriğini belirli bir yeni değere değiştirir.
‘Compare and Swap’ Komutunu Kilitleme için Kullanma Shared integer “lock” initialized to 0; Solution: do { while (compare_and_swap(&lock, 0, 1) != 0) ; /* do nothing */ /* critical section */ lock = 0; /* remainder section */ } while (true);
‘Compare and Swap’ Komutunu Kilitleme için Kullanma bellek konumunun içeriği ile karşılaştırılan değerin aynı olması durumunda, compare and swap metodunu çağıran process lock=1 yapar. Sonra process kritik bölümüne girebilir, compare and swap() için müteakip (subsequent) çağrılar cevaplanamaz, çünkü lock beklenen 0 değerinde değildir. Bir process kendi kritik bölgesinden çıktığında lock değerini tekrar 0 yapar ve böylece başka bir process’in kritik bölgesine girebilmesini sağlar.
Özel Makine Komutlarının Dezavantajları Donanımsal özel makine komutları meşgul beklemeye neden olduğundan bekleyen process de işlemci zamanı harcar. Bir process kritik bölgesine girmeden önce kilidi sınamakta, kilidin meşgul olduğu durumlarda bu sınamaları yineleyerek kilidin açılmasını beklemektedir. Bu durumda, erişeceği kilit meşgul olan bir process, sırası gelip CPU’ya anahtarlandığında kendisine ayrılan süre boyunca gerçekleşmeyecek bir koşulun oluşmasını bekleyerek, gereksiz yere CPU’yu meşgul edecektir.
Özel Makine Komutlarının Dezavantajları Özel makine komutları kritik bölge sorununun çözümünde karşılıklı dışlama (mutual exclusion) ve ilerleme (progress) gereksinimlerini karşılarlar. Ancak kritik bölge sorunun sınırlı bekleme (bounded waiting) gereksinimini karşılamak için diğer mekanizmalarla tamamlanmaları gerekir. Bir process kritik bölgesinden çıktığında birden fazla bekleyen process varsa hangi process’in gireceği belirsizdir, sonsuz bekleme durumu yani açlık (starvation) oluşabilir. Açlık (starvation) : Aynı kaynakları kullanan process’lerden bazılarının bekledikleri kaynaklara hiç erişememe durumu. Bekleyen process’ler sonsuz beklemeye girebilir.
Donanım + Yazılım Desteği ile Kritik Bölge Çözümleri
Semaforlar (Semaphore) 1965 yılında Edsger W. Dijkstra, process’ler arasındaki senkronizasyonu sağlamak için semafor yapısını geliştirmiştir. Semafor, işletim sistemi tarafından tanınan, donanım + yazılım desteği olan ve tamsayı (integer) değerlerini alabilen özel değişkenlerdir. Semafor değeri, yalnızca bir process’in herhangi bir zamanda erişebileceği ve değiştirebileceği paylaşılan bir değerdir. Semaphore, Latince kökenli dillerde deniz feneri anlamına gelmektedir.
Semaforlar (Semaphore) Semafor tamsayı değer saklayan bir nesne olarak düşünülebilir. Semafor üzerinde temel olarak DOWN =P(S) ve UP =V(S) isimli iki tür işlem tanımlıdır: P(S) semaforun değerini azaltmak. V(S) semaforun değerini arttırmak. Bu işlemler bölünemez(atomic) işlemlerdir ve işletim sistemi tarafından gerçekleştirilirler.
Semaforlar (Semaphore) Dijkstra çalışmasında, Almanca ‘Proberen : test et’ manasına gelen P operatörünü ve ‘Verhogen : arttır’ manasına gelen V operatörünü tamsayı tipinde değişken olan ‘S’ semaforu üzerinde uygulamıştır. P(S) : < while(S < = 0) {bekle}; S = S-1 > V(S) : < S = S+1 > P(S) 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şlemdir. V(s) ise S değişkenini bir artırmayı sağlayan bir işlemdir.
Semaforlar (Semaphore) ‘S’ semaforu bir tamsayıdır ve sadece wait() ve signal() atomik işlemleri tarafından erişilebilir ve değiştirilebilir. wait(S) işlemi P(S) yerine, signal(S) işlemi V(S) yerine kullanılır. Bir process kritik bölgesine girmeden önce wait(S) işlemini çalıştırır. S’nin içerdiği değere göre kritik bölgesine girer yada wait() işlemi üzerinde bekler. Kritik bölge çıkışında mutlaka signal(S) işleminin çalıştırılması gerekir.
Semaforlar (Semaphore) Semaforlar pozitif tamsayılar olarak tanımlanmasına rağmen çoğu kez gerçekleştirmede eksi sayılar da kullanılır. wait() semaforun değerini bir azaltır. signal() semaforun değerini bir arttırır. Bu iki yol dışında semaforun değerini değiştirmek mümkün değildir. wait ve signal işlemleri kesilemez.
Semaforlar (Semaphore) wait() ve signal() bölünemez (atomik) olarak gerçekleştirilirler. Bu sebeple wait() ve signal() içinde process’lere müdahele edilmesi ve CPU’nun bir başka process’e verilmesi söz konusu değildir. Process’ler kritik bölgelerine girmeden wait(), kritik bölgelerinden çıkarken de signal() işlemlerini yaparak karşılıklı dışlamayı garanti ederler.
Semaforlar (Semaphore) Semaforlar kullanım alanları ve tasarımları itibariyle ikiye ayrılır: İkili Semafor (Binary Semaphore) Sayma Semaforu (Counting Semaphore) ikili semafor sadece iki process arasında senkronizasyon sağlar. Semafor değeri 0 ve 1 ile kısıtlanmıştır. Bir mutex kilidi olarak da adlandırılır. Sayma semaforları ise istenilen miktarda process’i kontrol edebilir. Herhangi bir tamsayı değeri alabilirler.
İkili (binary) semaforlar Semaforların sadece 0 ve 1 değerleri alabildiği özel durumdur.
Semaforlar ile Karşılıklı Dışlama wait(S) : if S > 0 then S ←S -1 else /* S 0 ise */ S semaforu üzerinde bekle wait kendisine parametre olarak geçirilen semafor değişken değerini kontrol eder. Eğer S 0’dan büyükse S bir azaltılır ve process wait fonksiyonundan başarılı olarak geri döner ve işine devam eder. Eğer 0 ise process çalışma durumundan bloke durumuna geçer ve S değişkeni üzerinde bekler. signal(S) : if S değişkeni üzerinde bekleyen bir process varsa (bloke durumunda olup S değişkeni üzerinde bekleyen) then bu process uyandırılır else S ←S + 1 signal kendisine parametre olarak geçirilen semafor değişkeni üzerinde bekleyen process varsa bu process’i uyandırır. Bir başka deyimle bu process’in bloke durumdan hazır duruma geçmesini sağlar ve o process’e CPU verildiğinde kaldığı yerden devamı sağlanır.
Semaforlar (Semaphore) Eksi tamsayı değerleri de alabilen semaforlar Sayma Semaforu (Counting Semaphore) ya da genel semaforlar olarak adlandırılır. Semafor başlangıç değeri ≥ 0 olabilir. Başlangıç değeri ‘n’ olan bir semafor ‘n’ process tarafından kullanılır.
Semaforlar ile Karşılıklı Dışlama const int n = /* number of processes */ semaphore s=1; void P (int i) { while (true); wait(s); /* critical section */; signal(s); /* remainder */ } void main() parbegin (P(1), P(2), … , P(n));
Semaforlar (Semaphore) Bir process, wait () operasyonunu işletirse ve semaforun değerinin pozitif olmadığını bulursa beklemelidir (busy waiting). Meşgul bekleme yerine kendini bloke eder. Bloke edilen process semaforla ilişkilendirilir ve durumu “bekler- (waiting)” konumuna getirilir. Bloke edilen process semafor ile ilişkili bir bekleme kuyruğuna yazılır.
Semaforlar (Semaphore) Block() Process durumunu running den waiting e çevirir. Process’i bekler(waiting) kuyruğuna yerleştirir. Wake up() Bekler kuyruğundan semaforla ilişkili olan 1 process’i çıkarır ve hazır kuyruğuna koyar. Block() ve wakeup(): işletim sistemine ait standart sistem çağrıları ile sağlanır.
Semaforlar (Semaphore) Semafor S in üzerinde bekleyen, bloke edilmiş olan process, diğer process’lerden bazıları signal() operasyonu işlettiklerinde yeniden başlatılabilir. Process bir “wake up” operasyonu ile restart edilir. Bu process durumunu ‘beklerden’ ‘hazır’ durumuna geçirir.
Semaforlar (Semaphore) Her semafor integer bir değere ve bu semafor üzerinde bekleyen process listesine sahiptir (PCB listesine bir pointer kaydı). Bir process bir semafor üzerinde beklemeli ise semaforun proses listesine eklenir. signal() operasyonu process’i semafor listesinden çıkarır.
Semaforlar ile Karşılıklı Dışlama Örnek - Semafor kullanarak paylaşılan verilere erişen üç process.
Semaforlar (Semaphore) Semafor ile işlem yapmak, birlikte çalışan process’lerin yönetimine hem kuramsal hem de uygulanırlık açısından gerekli ve yeterli desteği sağlıyor olmalarına karşın azımsanamayacak tasarım ve programlama yükünü de birlikte getirirler. Process senkronizasyonu, process’lerin içine P() ve V() işlemlerinin serpiştirilmesini gerektirir. Bu durum programların okunurluğu ve anlaşılmasını olumsuz yönde etkiler. Bunun yanı sıra bu işlemlerin yanlış kullanımı, kimi zaman sistem kaynaklarının kilitlenmesine, dolayısıyla sistemin başarımının düşmesine ve güvenirliğinin zedelenmesine de neden olabilir.
Semaforlar (Semaphore) Semaforlar kullanıldığında da senkronizasyon hataları olabilmektedir. Tüm process’lerin kritik bölüme girmeden önce wait(), sonra ise signal() işlemlerini yapmaları gereklidir. Program geliştirici bu sıraya dikkat etmezse, iki veya daha fazla process aynı anda kritik bölüme girebilir. Bu durumlar programcılar arasında yeterli işbirliği olmadığı durumlarda da olabilmektedir.
Semaforlar (Semaphore) Kritik bölüm problemine ilişkin tasarımda oluşan sorunlardan dolayı kilitlenmeler veya eşzamanlı erişimden dolayı yanlış sonuçlar ortaya çıkabilmektedir. Bu gerekçeye dayalı olarak, process senkronizasyonunda alt düzey işlemleri doğrudan kullanmak yerine, bunlara dayalı, daha yalın ve sistemli izleyici (monitor) adı verilen üst düzey araçlardan yararlanılır.