Bölüm 3 / 16
İşletim sistemi
Süreç, iş parçacığı, zamanlama, kesme.
9 dakikalık okuma
Bir makinede 4-8 çekirdek var ama aynı anda yüzlerce program "çalışıyor" görünüyor. Bu yanılsamayı kuran yazılım işletim sistemidir. Bu ders dört temel kavramı kurar: süreç (process), iş parçacığı (thread), zamanlama (scheduling) ve kesme (interrupt). Süreç/thread ayrımı hem yazılı sınavın hem mülakatın demirbaş sorusudur; ilerideki async, Docker ve performans konularının tamamı bu dersin kelimeleriyle konuşur.
01Ne öğreneceksin
- İşletim sisteminin iki görevi: kaynak yönetimi ve soyutlama; çekirdek/kullanıcı modu
- Süreç: adres uzayı, PCB, beş durumlu yaşam döngüsü
- İş parçacığı ve süreç/thread karşılaştırması — sınav klasiği
- Zamanlama algoritmaları: FCFS, SJF, Round Robin, öncelikli; bağlam değiştirme maliyeti
- Kesmeler ve sistem çağrısı mekanizması
02İşletim sisteminin iki işi ve iki mod
İşletim sistemi (Windows, Linux, macOS, Android...) donanım ile programlar arasındaki katmandır ve iki iş yapar:
- Kaynak yöneticisi: CPU zamanını, belleği, diski ve aygıtları yüzlerce program arasında paylaştırır; birinin taşkınlığının diğerini çökertmesini engeller.
- Soyutlama katmanı: programlara donanımın ham hâlini değil, temiz
kavramlar sunar — disk sektörleri yerine dosya, fiziksel RAM yerine
adres uzayı, ağ kartı yerine soket. C#'ta
File.ReadAllTextyazarken disk kafasının nerede olduğunu düşünmemeni işletim sistemi sağlar.
Bu iki işin kalbi çekirdektir (kernel). Koruma, CPU'nun iki çalışma moduyla
sağlanır: çekirdek kernel modunda koşar — her komut, her adres serbesttir;
programlar kullanıcı modunda koşar — donanıma doğrudan dokunamaz, yalnızca
kendi belleğini görür. Program donanım isteyen bir iş istediğinde (dosya aç, paket
gönder, bellek iste) bir sistem çağrısı (system call) yapar: kontrollü bir
kapıdan kernel moduna geçilir, çekirdek işi yapar, sonuç döner. Senin
Console.WriteLine çağrın bile katmanlar altında bir write
sistem çağrısına iner. Bu geçiş ucuz değildir — "sistem çağrısı maliyetlidir, toplu
yap" ilkesi, ileride dosya G/Ç'yi tamponlu (buffered) yapmanın ve veritabanına tek
tek değil toplu gitmenin gerekçesi olarak karşına çıkacak.
03Süreç: çalışan programın kimliği
7. derste (sif-ilk-program) tanımı vermiştik: program diskte duran dosyadır, süreç (process) onun çalışan hâlidir. Şimdi içini dolduralım. Çekirdek her süreç için şunları kurar:
- Kimlik: benzersiz süreç numarası (PID).
- Adres uzayı: sürece özel, yalıtılmış bellek görünümü — kod, veri, heap ve stack bölgeleri (ayrıntısı sonraki derste, tb-bellek). Bir süreç diğerinin belleğini okuyamaz; Chrome çökünce Word'ün ayakta kalmasının nedeni budur.
- Kaynak tablosu: açık dosyalar, soketler, aygıt tutamaçları.
- PCB (Process Control Block): çekirdeğin süreç hakkında tuttuğu kayıt — PID, durum, yazmaç kopyaları, öncelik. Süreç duraklatılınca kaldığı yer buraya yazılır.
Süreç, yaşamı boyunca beş durum arasında dolaşır — bu diyagram yazılıda şema sorusu olarak gelir:
Yeni (new) → Hazır (ready) ⇄ Çalışıyor (running) → Sonlandı (terminated)
↑ |
| ↓ G/Ç veya olay bekliyor
└──── Bekliyor (waiting/blocked)
Kritik ayrım hazır ile bekliyor arasındadır: hazır süreç CPU'dan başka bir şey beklemez — sıra ona gelse hemen koşar; bekleyen süreç ise bir olayın (disk okuması, ağ cevabı, kullanıcı girdisi) tamamlanmasını bekler — CPU verilse bile yapacak işi yoktur. G/Ç bittiğinde süreç "bekliyor"dan "hazır"a döner, doğrudan "çalışıyor"a atlayamaz — zamanlayıcının onu tekrar seçmesi gerekir.
04İş parçacığı: süreç içindeki koşucular
İş parçacığı (thread), bir süreç içindeki bağımsız yürütme hattıdır — zamanlayıcının CPU'ya bindirdiği asıl birim süreçler değil thread'lerdir. Her süreç en az bir thread ile doğar; istediği kadar yenisini açabilir. Aynı sürecin thread'leri adres uzayını paylaşır: aynı heap'i, aynı global verileri görürler; yalnızca stack'leri ve yazmaç kopyaları ayrıdır. Paylaşım hem güçleri hem lanetidir — veri alışverişi bedavadır ama iki thread aynı veriye aynı anda yazarsa yarış durumu doğar; bu dert 5. dersin (tb-eszamanlilik) tamamıdır.
| Süreç (process) | İş parçacığı (thread) | |
|---|---|---|
| Bellek | Kendi yalıtılmış adres uzayı | Sürecin uzayını paylaşır; stack'i kendine ait |
| Yalıtım | Güçlü — biri çökse diğeri yaşar | Zayıf — bir thread'in ele alınmayan hatası tüm süreci düşürür |
| Oluşturma/geçiş maliyeti | Yüksek | Düşük |
| İletişim | IPC gerekir: boru (pipe), soket, paylaşımlı bellek | Ortak değişkenlerle doğrudan — ama senkronizasyon ister |
Ölçek hissi: bir web sunucusu tek süreçte onlarca thread ile yüzlerce isteğe bakar;
Chrome her sekmeyi ayrı süreç yapar — bellek öder, yalıtım satın alır
(bir sekme çöker, tarayıcı kalır). "Hangi durumda hangisi" kararının özü budur:
yalıtım istiyorsan süreç, ucuz paylaşım istiyorsan thread. C# tarafında
System.Threading.Thread ve thread havuzu vardır; modern .NET kodu
thread'leri elle değil async/await ve Task üzerinden
kullanır — mekanizması Hat 03'te (cs-async), temeli bu derstir.
05Zamanlama: 8 çekirdeğe 500 thread sığdırmak
Hazır thread sayısı neredeyse her zaman çekirdek sayısından fazladır. Zamanlayıcı (scheduler), her çekirdeğe sıradaki thread'i seçen çekirdek bileşenidir. Modern sistemler preemptif çalışır: thread'e bir süre dilimi (time slice / quantum, tipik olarak birkaç milisaniye) verilir; süre dolunca donanım zamanlayıcısının kesmesiyle thread'in elinden CPU alınır — kibarca bırakması beklenmez. Saniyede yüzlerce bu geçiş, "her şey aynı anda çalışıyor" yanılsamasını üretir.
Klasik algoritmalar — yazılı sınavın hesap soruları buradan gelir:
- FCFS (First Come First Served): ilk gelen bitene kadar koşar. Adil görünür ama kısa işler uzunların arkasında yığılır (konvoy etkisi).
- SJF (Shortest Job First): en kısa iş önce — ortalama bekleme süresini kanıtlanabilir biçimde en aza indirir ama işin süresini önceden bilmek gerekir ve uzun işler sürekli ertelenebilir (starvation).
- Round Robin: hazır kuyruğu sırayla dolaşılır, herkese eşit quantum. Etkileşimli sistemlerin temelidir. Quantum küçükse geçiş maliyeti büyür, büyükse tepkisellik düşer — ayarı bir dengedir.
- Öncelikli: yüksek öncelikli önce; gerçek sistemler bunu çok seviyeli kuyruklarla harmanlar ve bekleyenlerin önceliğini zamanla yükseltir (aging) — starvation'ın panzehiri.
- Gerçek zamanlı sistemlerde (uçak, ABS freni) zamanlama garantilidir — "genelde hızlı" değil "her zaman süresinde" hedeflenir; ayrı bir dünyadır, adını bil.
Her thread değişiminde bağlam değiştirme (context switch) yaşanır: koşanın yazmaçları PCB'ye yazılır, yenisininki yüklenir — ve görünmez vergi ödenir: CPU önbellekleri (2. ders) yeni thread'in verisiyle dolana kadar soğuktur. Mikrosaniyeler düzeyindeki bu maliyet, binlerce thread açan tasarımların neden yavaşladığının cevabıdır; .NET'in thread havuzu ve async modeli tam bu israfı azaltmak için vardır.
06Kesmeler: sistemin sinir uçları
2. derste G/Ç yöntemi olarak görmüştün; şimdi resmin bütünü. Kesme (interrupt), CPU'nun elindeki işi bırakıp önceden kayıtlı bir kesme işleyiciyi (interrupt handler) çalıştırmasına yol açan sinyaldir. Üç kaynağı vardır:
- Donanım kesmesi: aygıtlardan gelir — tuşa basıldı, disk okuması bitti, ağ paketi düştü, zamanlayıcı vurdu. Preemptif zamanlamayı mümkün kılan, bu sonuncusudur: çekirdek, periyodik zamanlayıcı kesmesiyle düzenli olarak söz hakkı kazanır.
- Yazılım kesmesi / tuzak (trap): programın bilerek ürettiği geçiş — sistem çağrısının kapısı.
- İstisna (exception): hatalı komutun tetiklediği kesme — sıfıra bölme,
geçersiz bellek erişimi. C#'ta yakaladığın
NullReferenceException'ın (Hat 03'te derinleşecek) donanım katındaki atası budur: geçersiz adres → işlemci istisnası → çekirdek → çalışma zamanına iletim.
Akışı canlandır: klavyede A'ya bastın → klavye denetleyicisi kesme çeker → CPU, koştuğu thread'i askıya alıp işleyiciye atlar → işleyici karakteri tampona yazar, bekleyen süreci "hazır"a taşır → CPU kaldığı işe döner. Milisaniyenin altında biten bu zincir, saniyede binlerce kez döner. Kesme işleyicileri bu yüzden kısa tutulur: uzun iş, işleyicide değil sonraya bırakılan görevlerde yapılır — "kesmede az iş yap, kuyruğa at" deseni, ileride mesaj kuyruklu mimarilerde (Hat 19) aynı fikirle karşına çıkacak.
07Pratik: süreçleri izlemek
Teoriyi araçla bağla; bu araçlar günlük işinin parçası olacak:
- Windows: Görev Yöneticisi (Ctrl+Shift+Esc) → Ayrıntılar sekmesi: PID,
durum, CPU yüzdesi, bellek.
tasklistaynı listeyi terminalde verir. - Linux:
ps auxanlık liste;htopcanlı görünüm — üst satırlardaki load average, hazır kuyruğunun uzunluğunu özetler.kill <PID>sürece kapanma sinyali gönderir,kill -9çekirdeğe "sorgusuz sonlandır" der (süreç temizlik şansı bulamaz — son çare). Ayrıntı Hat 17'de. - C# içinden:
Process.GetProcesses()süreçleri listeler,Process.Start("notepad")yeni süreç açar,Environment.ProcessIdkendi PID'ini verir.
Durumları sahada okumayı öğren: bir sürecin CPU'su %0 ve durumu "bekliyor" ise tembel değil, büyük olasılıkla G/Ç ya da kilit bekliyordur; CPU %100'de tek çekirdeği döven tek thread'li süreç, "makine güçlü ama uygulama yavaş" şikâyetinin tipik failidir. "Yanıt vermiyor" penceresi ise UI thread'inin uzun bir işle bloke olması demektir — kullanıcı arayüzü olan her platformda kural aynıdır: uzun işi UI thread'inde yapma.
08Mini alıştırma — Süreç gözlemevi
Yaklaşık 15-20 dakika · terminal + dotnet new console -o surecler
- Sistemindeki süreçleri listele (
htop/ Görev Yöneticisi). En çok bellek kullanan 3 süreci ve PID'lerini not et. Tarayıcın kaç süreç çalıştırıyor? - C# programı yaz:
Environment.ProcessId'yi veProcess.GetProcesses().Length'i yazdır; ardındanConsole.ReadLine()ile beklet. Beklerken kendi sürecini araçta bul: durumu ne, CPU'su neden %0? (Cevabı bir cümle yaz: hangi durumda, neyi bekliyor?) - İki thread'in gerçekten dönüşümlü koştuğunu gör: iki
Threadbaşlat; biri "A", öbürü "B" yazsın (her biri 20 kez,Thread.Sleep(50)ile). Çıktıdaki harf sırası her çalıştırmada aynı mı? Neden değil — cevabında "zamanlayıcı" ve "quantum" kelimeleri geçsin. - Kâğıtta zamanlama hesabı: P1=24 ms, P2=3 ms, P3=3 ms aynı anda gelsin. FCFS (sıra P1,P2,P3) ve Round Robin (quantum 4 ms) için ortalama bekleme süresini hesapla. (FCFS: (0+24+27)/3 = 17 ms; RR: P2 4. ms'de, P3 8. ms'de başlar — hesabını yap, konvoy etkisini gör.)
09Kendini sına
Kullanıcı modu / kernel modu ayrımı neden var? Sistem çağrısı bu resmin neresinde?
Programların donanıma ve birbirlerinin belleğine doğrudan erişimini engellemek için: kullanıcı modunda ayrıcalıklı komutlar ve yabancı adresler yasaktır, çekirdek kernel modunda her şeye erişir. Program donanım gerektiren iş istediğinde sistem çağrısıyla kontrollü kapıdan çekirdeğe geçer; çekirdek işi yapıp sonucu döndürür. Bu geçişin maliyeti, G/Ç'yi tamponlu ve toplu yapma pratiğinin gerekçesidir.
Süreç durum diyagramını çiz; "hazır" ile "bekliyor" farkını açıkla.
Yeni → hazır ⇄ çalışıyor → sonlandı; çalışıyor → (G/Ç/olay beklerse) bekliyor → (olay bitince) hazır. Hazır süreç yalnızca CPU bekler — seçilse hemen koşar. Bekleyen süreç bir olayın bitmesini bekler — CPU verilse de iş yapamaz. Olay tamamlanınca bekleyenden hazıra geçer; çalışıyora doğrudan atlayamaz, zamanlayıcının seçmesini bekler.
Süreç ile thread arasındaki farkları bellek, yalıtım ve maliyet açısından karşılaştır. Hangi durumda hangisini seçersin?
Süreç kendi yalıtılmış adres uzayına sahiptir; çökmesi diğerlerini etkilemez ama oluşturması ve arasında iletişim (IPC) pahalıdır. Thread'ler aynı sürecin belleğini paylaşır: iletişim bedava, oluşturma ucuz; ama yalıtım yok — bir thread'in hatası süreci düşürür ve paylaşılan veri senkronizasyon ister. Seçim: yalıtım/güvenlik kritikse süreç (tarayıcı sekmeleri), yoğun veri paylaşımı ve hafiflik gerekiyorsa thread (web sunucusunun istek işçileri).
Preemptif zamanlama nedir ve hangi mekanizma sayesinde mümkündür? Round Robin'de quantum seçiminin iki ucu neye mal olur?
Preemptif zamanlamada çekirdek, süre dilimi dolan thread'den CPU'yu zorla alır; thread'in gönüllü bırakması beklenmez. Bunu mümkün kılan, periyodik donanım zamanlayıcı kesmesidir — her vuruşta kontrol çekirdeğe döner. Round Robin'de quantum çok küçükse zaman, bağlam değiştirme ve önbellek ısınması maliyetine gider; çok büyükse etkileşimli işler sırada uzun bekler, sistem hantal hissedilir.
10Sınav köşesi
Yazılıda nasıl sorulur
Dört kalıp: (1) Tanım — "Çalışan programa ne denir?" (süreç), "Aynı süreç içinde belleği paylaşan yürütme birimleri?" (thread), "İşletim sisteminin çekirdeğine ne denir?" (kernel). (2) Durum diyagramı — "G/Ç bekleyen süreç hangi durumdadır?" (bekliyor/blocked), "G/Ç bitince hangi duruma geçer?" (hazır — çalışıyor değil; en sık tuzak budur). (3) Hesap — FCFS/SJF/RR için ortalama bekleme süresi; Gantt şeması çizerek çöz, quantum'u ve geliş sıralarını dikkatli oku. (4) Eşleştirme — algoritma/özellik: "ortalama beklemeyi en aza indiren?" (SJF), "eşit süre dilimi dağıtan?" (Round Robin), "starvation'a karşı önlem?" (aging).
Sözlüde nasıl anlatılır — 2 dakikalık taslak
"Süreç ile thread farkı nedir?" en olası sorudur; düzen: (1) Tanımlar — süreç yalıtılmış adres uzayına sahip çalışan program, thread onun içindeki yürütme hattı. (2) Üç eksenli karşılaştırma: bellek, yalıtım, maliyet — tabloyu konuşarak ver. (3) Somut örnek seç: "Chrome sekme başına süreç kullanır, yalıtım için bellek öder; web sunucusu istekleri thread'lerle karşılar, paylaşım için senkronizasyon öder." (4) Kapanış köprüsü: "Paylaşılan veri yarış durumu doğurur; kilit ve deadlock konusu buradan açılır" — hem hâkimiyet gösterir hem mülakatı senin güçlü alanına çeker.
