Bu yazıda, hem lisans hem yüksek lisansta aldığım İşletim Sistemi dersinden
gözlemlerim ve notlarımın, yazılımcı bakış açısı ile ele alınmaktadır.
Yazılımcılara genel kültür olacağına inandığım ve temel seviyede bilgi vermesi amacıyla konular, basitçe ifade edilmiştir.
Aşağıdaki başlıklara tıklayıp, ilgili konuya ulaşabilirsiniz.
- İşletim Sistemi Nedir?
- Program vs Process
- Thread Yapısı
- İşlem Senkronizasyonu
- CPU Scheduling
- Main Memory
- Deadlock - Ölümcül Kilitlenme
İşletim Sistemi Nedir?
İşletim Sistemi, son kullanıcıların kullandığı uygulamalarla donanım
arasında haberleşmeyi sağlayan yazılımlardır. Bilgisayardaki
işlemleri gerçekleştiren kaynakların - CPU(işlemci), Memory(bellek),
I/O(Input-Output) - yönetimini sağlayan kontrol yazılımlarıdır. Bu
kaynaklar, bir bilgisayarın temel işlevleri olan veriyi işleme, saklama,
taşıma ve kontrol işlemlerinden sorumludur.
Buradan çıkarılabilecek temel sonuç; bilgisayar kaynaklarının etkili
kullanımını sağlayıp (kaynak yöneticisi), kullanıcıya kullanım
kolaylığı sağlamasıdır.
Aşağıdaki görselde işletim sisteminin, bilgisayar sistemindeki yeri daha iyi
anlaşılacaktır.
İşletim sisteminin ne iş yaptığı, bakış açısına göre değişir.
Normal kullanıcılar, kolay kullanım ve iyi performans bekler. Kaynak
kullanımını önemsemezler.
Yazılımcı bakış açısı ile düşünürsek, geliştirdiğimiz uygulamaların
sistemi kilitlememesi, yerinde değişken kullanımı, işlemlerin hızlı cevap
vermesi gibi konuları dikkate alarak, son kullanıcıya kesintisiz hizmet
sağlamaya devam etmesini önemseriz.
İşletim sistemleri interrupt driven (kesme yönenilmli) özelliğinden
dolayı olmazsa olmazdır. Çalışma rutinin değiştirme yolu interruptlardan
geçer. Yazılım tarafından üretien trap/exception, hata fırlatarak
işlemi kesebilir. Programımızda çalışan kodlarda
exception handling- hata yönetimi önemlidir.
Program vs Process
Program ve process kavramları sıkça karıştırılır. Kesin bilgi olarak;
Program != Process
Program, pasif bir varlıktır. Program yazıldı, kaynak kod derlenerek
makine koduna döndü. Process ise çalışan bir programdır. Bir process,
"programı çalıştır" dediğimiz anda diskten RAM'e alınır ve CPU'da
çalışması için sırasını bekler.
Process olması için aşağıdaki yapıların olması gerekir.
Text: Program kodu.
Data: Program kapsamında global değişkenlerin bulunmasıdır.
Stack: Geçici değişkenleri tutar.
Counter: Programın bir sonraki çalışacak adımını tutar.
Heap: Dinamik olarak yapılan memory allocation'dur.
Text, data sabittir. Stack, counter ve heap ise değişkendir.
Process Control Block (PCB) veri yapısı, processlerin takip
edilebilmesi için kullanılır. İşlemin künyesi olarak da düşünülebilir. Temel
bulunan kısımlar;
- Process state - işlemin durumu
- Process id - tekil bir id
-
Program Counter - Program çalışırken hangi satırda/ bir sonraki
adımda ne çalışacak
- Register - Processle ilgili bilgiler tutulur.
- Memory Limit - Kaynak, kapasite tanımı
- Açık dosyaların bilgisi - I/O bilgisi
Processlerin aşağıdaki gibi durumları vardır. Yaşam döngüsünü anlarsak,
çalışma mantığını anlayabiliriz.
new: Process yaratılmış demektir.
ready: Process çalışmak için hazırdır ve CPU'dan sıra bekliyor.
Farklı bir processi veya kaynağı beklemektedir.
running: CPU tarafından ready kuyruğundan işlemin çalıştırılmak
üzere alınmasıdır.
waiting: I/O işlemi başladığında oluşacak bir durumdur.
terminated: İşlemin bitmesidir.
Yukarıdaki görselde processin yaşam döngüsü üzerinden çalışma mantığına yer verilmiştir. Dikkat
edilecek nokta,
ready-running-waiting durumları arasında bir
döngü olmasıdır.
ready-running arasında scheduler dispatch devreye girer.
ready-running durumları arasındaki waiting durumunda
I/O işlemi çalışıp bitmektedir.
Waiting durumundan ready durumuna geçmesi, tekrar işlemcide çalışmaya
hazır ve sırası geldiğinde runningde çalışabileceğini belirtir.
Running'den ready durumuna geçmesi durumu herhangi bir interrupt
oluşması ya da time quantum ile çalışan algoritmanın devreye girmesinden
kaynaklı olabilir.
Thread Yapısı
Araştırma yaparken,
"Processler kollarsa, threadler ise parmaklarıdır." analojisine denk geldim. Bu sayede Process ile thread arasındaki farkları daha iyi
anladım.
Bir thread'in var olması için process var olmalıdır. Bir processte
birden fazla thread olabilir. Threadlerde amaç, işlemci zamanını efektif
şekilde kullanmaktır. Bir kullanıcıya ait bir processler CPU zamanının
tamamını kullanmak mümkün değildir. Bir kullanıcıya ait birden fazla
processin aynı anda çalışmasına izin verilir.
Faydaları; yanıt verilebilirlik artar, daha kolay kaynak paylaşımı ve daha
az maliyetli kaynak kullanımı sağlar. Daha az yer kapladığı için
ölçeklenebilirlik kolaydır.
Çok çekirdekli/işlemcili sistemlerde karşılaşılan zorluklar; etkinlikleri ve
veriyi bölmek, denge, veri bağlılığı ve test/hata ayıklama sürecidir. Bu
yüzden paralellik(parallelism) ve eş zamanlılık (concurrency) konuları
gündemdedir.
Paralellik: Sistemin aynı ana birden fazla iş yapabilmesi. Çoklu
işlemcili ve çekirdekli sistemler paralel çalışmayı destekler.
Eş zamanlılık: Birden fazla işin ilerlemesini destekler. Zaman
paylaşımlı sistemlerde, sistemin herkesin çalışmasına imkan verecek şekilde
işlemleri yürütebilmesi için işlemler arasında kısa zamanda geçişler yaparak
aynı anda çalışıyor izlenimi verilmesidir.
Single threaded ve multi process arasındaki en önemli fark her bir thread
için register ve stacklerin ayrı olmadıdır. Kod ve data alanlarının sabit
olduğunu processler bölümünde değinmiştim.
Amdahl Yasası'nda bilmemiz gereken konu, programın
paralelleştirilmesiyle alakalıdır. Çekirdek sayısı iki katına çıktıkça
performans iki katına çıkmaz. Paralel ve seri işlemlerin oranlarına göre
değişir.
Thread yönetiminde
kernel ve kullanıcı threadlerinin eşleşmesi gerekir. Üç tip bulunur.
Many to One yapısında kernel engellenirse bütün kullanıcılar
engellenmiş olur. Fakir işi bir yapı gibi akıllarda kalabilir. Çok
kullanıcı threade karşı bir kernel threadin eşleşmesidir.
One to One yapısında bir kullanıcı
threadi için bir kernel threadi eşleşmiştir. Kaynakları bol bol tüketir ve
bu yönden zengin işi şeklinde akıllarda kalabilir. Kernel yönetiminin
sorun olması, dezavantaj yaratabilir.
Many to Many yapısında birden çok kullanıcı threadlerine karşılık
birden fazla kernel thread ile eşleşmesidir. Bir kernelde engelleme varsa
diğerleri çalışmaya devam edebilir.
Bir process birden fazla uygulamada olamaz ama bir programın birden fazla
processi olabilir.
İşlem Senkronizasyonu
Yazılımcının görevi işlemler arasında haberleşme ve senkronizasyonu
sağlamasıdır. Bu noktada Interprocess communication (IPC) haberleşme için
mekanizma sunmaktadır.
Paylaşılan Bellek: Aynı bellekte birden fazla processin kullanılması
Message Passing: Mesaj kuyruğu vardır. Biri yazarken diğeri okuma
işlemi yapabilir.
Bilinmesi gereken temel kavramlar
Race condition: Birden fazla process, aynı kaynağa erişmeye çalışıyor
ama hangisinin önceden çalışacağı bilinmiyor. İşlemlerin farklı senaryolarda
farklı sonuç elde etme durumudur.
Critical section: Programlarda eş zamanlı olarak çalışan
processlerden korunan bölgedir. Korunmazsa hatalı sonuçlara sebebiyet
verebilir. Kritik alanlar, girişine ve çıkışına yazılacak kodlarla korunur.
CPU Scheduling
Processleri nasıl sıraladığımız ve işlemcinin nasıl çalıştıracağına karar
veren bir mekanizmadır. Birden fazla processin parallel olarak çalışması
(concurrency) ve işlemler arası zaman paylaşımı bu işin temel konusudur.
Bunun için değişik algoritmalar mevcuttur. İşletim sistemleri aynı zamanda
bir process olduğundan process yönetimi olmadan olmaz.
Zamanlayıcı, işlemciyi çok iyi kullanmalı ve işlemciden maksimum
performansı almasını sağlamalıdır.
İşlem davranışlarında işlemler; CPU burst veya
I/O burst olabilir. Bunlar bir döngü halinde çalışırlar.
Algoritmalar iki temel gruba ayrılırlar.
-
Preemptive - Kesintili: İşlemcide işler çalışırken yarım
bırakılıp başka bir işle değiştirilebilir. Zamanı dolunca farklı bir iş
atanabilir.
-
Non-preemptive - Kesintisiz: Bir iş atandı mı o iş bitene kadar
işlemciden alınmıyor.
Short-Term Scheduler
Çok uzun süre işlemcide olması istenmeyen ve CPU'ya az ihtiyaç duyan
işlemler için kullanılır. Kullanıcı ile etkileşime giren veya hızlı cevap
beklediğimiz uygulamalarda rastlarız.
Örnek olarak bir butona tıkladığımızda hemen cevabın gelmesidir.
Long-Term Scheduler
Uzun sürecek işlemlerde kullanışlıdır. Kullanıcı ile etkileşime girmeyen
işlerde tercih edilir. Örneğin, yedek alma işlemi, toplu işlemlerde
kullanışlıdır. İş bitene kadar CPU da kalabilir. Genellikle, sunucu
mimarisinde kullanılır.
Zamanlayıcı kriterleri - işi iyileştirme kriterleri diyebiliriz.
-
CPU Utilization: İşlemciyi ne kadar yoğun tutarsak o kadar
iyidir.
-
Throughput: Birim zamanda tamamlanan, sistemi terk eden işlem
adedi.
-
Turnaround Time: İşlemin sisteme girişi ve çıkışı arasında geçen
süredir. İşlemin başlangıç ve bitiş süresi de denir.
-
Waiting Time: CPU'ya erişmek için ready kuyruğunda ne
kadar bekledi.
-
Response Time: İşlemin cevap verme süresi. Bir işin işletim
sistemine teslim edilmesinden, sonlanana(submit) kadar geçen süre de
denilebilir.
Hedeflerimiz;
- Maksimum CPU Kullanımı
- Maksimum Throughput
- Minimum Turnaround Time
- Minimum Response Time
- Minimum Waiting Time
Duruma göre değişen algoritmalar var. Her birinin avantajları ve
dezavantajları vardır. İşlemlere göre aşağıdakiler uygulanabilir.
First Come / First Served : İlk gelen ilk hizmeti alır.
Non-preemptivedir.
Shortest Job First: En kısa burst(çalışma zamanı) olan ilk hizmeti
alır.
Priorty Scheduling: İşlemlerle ilişkili bir öncelik değeri vardır ve
düşük sayıda olan ilk hizmeti alır.
Round Robin: İşlemlerin time quantum süresi başına sırasıyla
çalıştırılmasıdır. Preemptivedir.
Shortest Remaining Job First: Shortest Job First
algoritmasına preemption eklenmiş halidir. Sisteme varış süresine bakıp, en
kısa işin öncelikli çalıştırılması durumudur.
Context switch: Bir processten diğerine geçme işlemidir. İki process
arasındaki geçişler PCB yapısına kaydedilir. Context switchin çok fazla
olması iyi değildir. CPU zamanı israf edilecektir ve her değişim
maliyetlidir. Scheduling bölümünde değinme sebebim, işlerin paylaştırılması
noktasında context switchlere dikkat edilmesi gerektiğidir.
Main Memory
Bir programın çalışması için data ve komutların bellekte olması
gerekmektedir. Makine dilindeki bir programın diskten RAM'e yüklenmesi,
processlerin çalışması için ilk şarttır. Diskte program
çalışmamaktadır.
Kaynak sınırlı olduğundan processin belleğe giriş çıkış zamanının
yönetilmesi problemdir. Bu yüzden bellek yapısını anlamak gerekir.
Programlar, kod ve datadan oluşur. Kaynak kodlarında satır sayıları var,
derlenirken adres ortaya çıkıyor. Program çalışırken fiziksel adres üzerinde
işlem yapar.
Processlerin çalışırken bellekte konumlandırılabilmeleri için base ve limit
adresleri vardır.
Base register: Programın ilk kodu oradadır. Process çalışırken başlangıç
noktası olarak adresini sıfır zanneder.
Limit register: İşlemler, bu linit aralığında çalışır. Base adresleri
eklenerek gerçek adreslerine dönüştürülür. Sonrasında process, bu aralıkta
konumlanır.
Logical adres, erişmek istenen adrestir ve işlemci üretir. Fiziksel adres
ise bellekte görünen adrestir.
Yukarıdaki görselde görüleceği gibi; işlemin adresi base adress ile base ve
limit adresinin toplamı arasında olmalıdır. Aralık dışındaysa hata
dönecektir ve belleğe alınamayacaktır.
Üç önemli zaman bulunuyor.
Compile Time: Derleme zamanı. Daha önceden derlenmiş, önceden
fiziksel adresi biliyoruz.
Load Time: Yükleme zamanı. Program çalıştı, belleğe yüklenme işlemini
işletim sistemi yapar. Bu zamanda sırasıyla linker vasıtasıyla 3.
parti kütüphanelerin bağlanması, loader vasıtasıyla kütüphaneler ve
kodların yüklenmesi sağlanır.
Execution Time: Çalıştırma zamanı. Bellek üzerinde işlemler için bazı
değişiklikler yapılıyor.
Load ve Execution Time'de base register sürekli değişiyor.
Swapping: Bellekteki işlemlerin diske alınması veya diskteki bir
işlemin de bellekte boş bir yere alınmasıdır.
Swap in: Diskten belleğe geçiş
Swap out: Bellekten diske geçiş
Tabi her process bellekte aynı miktarda yer kaplamıyor. Bu geçişler
sırasında boşluklar oluşabilir.
Internal fragmentation: Processe ayrılan alan içerisindeki
boşluklardır.
External fragmentation: Eklenen processler arasındaki boşluklardır.
Processlerin belleklere yerleştirilmesi sırasında üç farklı yaklaşım vardır.
First-fit: İlk bulduğu, sığabilen boşluğa processin
yerleştirilmesidir. Daha hızlıdır ve boyutlara bakmaz.
Best-fit: External fragmenti en küçük olanı bulur yani boşluklara
bakıp en iyi yeri bulur.
Worst-fit: "Daha araya process eklenebilir mi?" sorusunun
cevabını verir.
Fragmentleri azaltmak için yapılan işlemlere Compaction denir.
Processleri bellekte oynatarak boş alanları arttırmaya çalışır. Processler
bölünmüyor fakat maliyet artacaktır.
Segmentation - Processleri ihtiyaca göre RAM'e dağıtıyor. "External
fragmentation"a sebep olur.
Paging - Segmentation'den farklı olarak
sabit boyutlu sayfalar oluşturuluyor. "Internal framentation"a sebep
olur.
Deadlock - Ölümcül Kilitlenme
İşlemler çalışırken neyin ne zaman hangi sırada çalışacağını bilemeyiz.
Kaynağa erişme isteğinden dolayı processlerin birbirini kilitlemesi sonucu
hiç bir işlem çalışamaz ve deadlock oluşur. Yazılımcılar olarak hatalı kod
yazmak, işletim sisteminin sunacağı kaynakları hatalı kullanma sonucunda
deadlocka sebep olabiliriz. Örnek bir senaryoda multi thread kurgusu doğru
kurgulanmazsa paylaşımlı olarak thread kullanılma durumu olabileceğinden
deadlocka sebep olabilir.
Kaynakların kullanımı için aşağıdaki sıra takip edilmelidir.
- Kaynağı iste
- Kullan
- Kaynağı bırak
Deadlock oluşması için aşağıdaki dört şartın sağlanması gerekir.
-
Mutual exclusion: İki processin birbirini bekleme durumudur.
Herhangi bir T anında bir kaynakta sadece tek process çalışmalıdır.
Çalışmayıp aynı kaynağa erişme isteği doğuyor.
-
Hold and wait: Process kaynağı tutuyor ama başkasının da
kaynağını tutup diğer işlemin beklemesine yol açıyor.
-
No preemption: Scheduling ile ilgili bir konudur. Bir process
kaynağı aldığı zaman işi bitene kadar elinden alınmıyor.
-
Circular: Eğer kaynak ve işlem arasında aşağıdaki görseldeki gibi
bir döngü varsa, deadlock oldu denilebilir.
Görselde, Process 1, Resource 1'i talep etmiştir. Aynı zamanda Process 2
Resource 1'i tutmaktadır. Döngünün devamında Process 2, Resource 2'i talep
etmiştir. Aynı zamanda Process 1, Resource 2'yi tutmaktadır. Kaynağı serbest
bırakan bir işlem olmadığı için de kilitlenme ortaya çıkacak ve deadlock
kaçınılmaz olacaktır.
Özetle;
- Eğer döngü yoksa, deadlock oluşmaz.
- Döngü varsa kaynağa bakılır.
-
Eğer kaynak başına bir örnek varsa kesinlikle deadlock oluşur.
-
Eğer birden fazla varsa olabilir de olmayabilir de incelenmesi gerekir.
Deadlock önlemek için yollar var ama gerçekleştirmek zordur.
Birden fazla processin aynı anda çalışıp kaynağa erişmesine izin
verilmiyor.- Mutual exclusion
İstekleri tek tek işleyip hold and waiti kaldırmak. En başta istediği
kaynakğı öğrenip varsa sağlamak yoksa bekletmek.
Sistemi preemptive yapmak. Belirli bir sürede daha önceden verilen
kaynaklar, zorla elinden alınamaz.
Kaynak Önerisi
-
Üniversitelerde gösterilen ve dinazorlu kitap olarak da bilinen aşağıdaki kitap,
kitabı okumak istemezseniz slayları da mevcuttur.
"Operating System Concepts", 9. Edition, Abraham Silberschatz, Peter B. Galvin, Greg Gagne Slaytları için
tıklayınız. -
Türkçe Youtube Kaynağı olarak Şadi Evren Şeker hocanın Bilgisayar Kavramları kanalında, İşletim
Sistemleri oynatma listesinde özet olarak anlatılmaktadır.
Oynatma Listesi için
tıklayınız.
Keyifli ve faydalı olmasını umarak, çalışmalarınızda kolaylıklar
diliyorum :)
Yorumlar
Yorum Gönder