Ders 03 / 22
Sinyaller
Yedi ağır sürece sonlandırma isteği gönderildiğinde 2'si kabul ediyor, 5'i yok sayıyor; zorlayan sinyalde 7/7 bitiyor ama 2 sürecin temizliği yarıda kesiliyor. Komut her durumda 0 döndürdüğü için beklemeden verilen tanı yedi hedefin yedisinde de yanlış.
İçindekiler
Önceki ders bir sinyalin kenarından geçti: uçtermin kapandığında kapanma sinyali oturumun başına iletildi, kabuk onu kendi işlerine yaydı ve işlerin bir bölümü sinyali yok saydı. Yok saymanın kendisi ölçülmedi. Bu ders sinyalleri doğrudan ele alır.
Ölçtüğü cümle tektir: sonlandırma isteği bir istektir. Komutun hatasız dönmesi hedefin bittiği anlamına gelmez, ve aradaki fark sayılabilir.
Sinyal Nedir, Ne Değildir
Sinyal, çekirdeğin bir sürece ilettiği kesme bildirimidir. İçinde veri taşımaz; yalnız kimliği vardır. Süreç bir sinyali aldığında üç şeyden biri olur: sürecin o sinyal için tanımladığı işleyici çalışır, sinyal yok sayılır, ya da sinyalin varsayılan eylemi uygulanır. Varsayılan eylem sinyalden sinyale değişir — sonlandırmak, durdurmak, sürdürmek ya da hiçbir şey yapmamak.
Kabuk Programlama kursundaki trap tam olarak birinci seçeneği kurar: betiğin sinyal
işleyicisini tanımlar. Buradaki fark bakış yönüdür — orada sinyali alan taraf yazıldı,
burada gönderen taraf ölçülür.
| Sinyal | Varsayılan eylem | Yakalanabilir mi | Ne için |
|---|---|---|---|
SIGHUP |
sonlandır | evet | denetleyen uçtermin gitti; birçok servis bunu yeniden okuma isteği sayar |
SIGINT |
sonlandır | evet | uçterminden kesme (Ctrl+C) |
SIGQUIT |
sonlandır ve döküm al | evet | uçterminden çıkış isteği |
SIGTERM |
sonlandır | evet | sonlandırma isteği — nazik biçim, varsayılan |
SIGKILL |
sonlandır | hayır | zorlayan sinyal — süreç söz sahibi değildir |
SIGSTOP |
durdur | hayır | süreci dondurur |
SIGCONT |
sürdür | evet | durdurulmuş süreci sürdürür |
SIGUSR1, SIGUSR2 |
sonlandır | evet | anlamı programın kendi sözleşmesindedir |
SIGPIPE |
sonlandır | evet | okuyan ucu kapanmış boru hattına yazma |
SIGCHLD |
yok say | evet | bir çocuk süreç bitti ya da durdu |
İki satır ötekilerden ayrıdır. SIGKILL ve SIGSTOP yakalanamaz, yok sayılamaz ve
engellenemez; kararı çekirdek verir, süreç haberdar bile olmaz. Bunun bedeli tam olarak
budur: zorlayan sinyalle ölen bir süreç, kendi kapanış yordamını hiç çalıştıramaz.
Sinyallerin numaraları da vardır ama numaralar her mimaride aynı değildir. Taşınabilir yazım
adla yapılır: kill -TERM yazılır, sayı yazılmaz.
Sinyal Göndermek
Sinyal gönderen komutun adı kill’dir ve adı yanıltıcıdır: komut süreç öldürmez, sinyal
iletir. Hangi sinyalin iletildiği seçeneğe bağlıdır, seçenek verilmezse sonlandırma isteği
gönderilir.
$ kill -TERM 1128 $ echo $? 0 $ kill -0 1128 # sinyal gonderme , yalnizca ulasilabilir mi diye bak $ echo $? 0 $ pkill -TERM -u uygulama kuyruk-isleyici $ kill -TERM -1014 # eksi isaretli sayi: sinyal SUREC OBEGINE gider
Bu döküm örnektir ve çalıştırılmamıştır. Dört ayrıntı taşıyor. kill -0 hiçbir sinyal
göndermez; yalnız hedefin var olup olmadığını ve ona sinyal gönderme yetkisinin bulunup
bulunmadığını sınar — doğrulamanın aracı budur. pkill hedefi ada ve kullanıcıya göre seçer;
birinci dersteki ölçü burada geçerlidir, ad bir kimlik değil etikettir. Eksi işaretli sayı
hedefi süreç öbeğine çevirir: bir boru hattının tek üyesine değil, tamamına gönderir.
killall da ada göre çalışır ve davranışı sistemler arasında değişebildiği için, taşınabilir
betiklerde pkill yeğlenir.
En kritik ayrıntı ikinci satırdadır. kill komutunun çıkış kodu sinyalin iletilip
iletilmediğini bildirir. Hedefin sinyali nasıl karşıladığı, işleyicisinin ne yaptığı, sürecin
bitip bitmediği bu koda hiç yansımaz. Kodu 0 gören operatörün “iş bitti” demesi, ölçülmemiş
bir tanıdır.
- SY15. Hedef küme, kurgu sunucudaki sürekli ağır desenli süreçlerdir.
- SY16. Süreçlerin bir bölümü sonlandırma isteğini yok sayar; ortak tanımdaki
sinyal_yok_sayaralanı bunu taşır. Zorlayan sinyal yok sayılamaz. - SY17. İsteği kabul eden bir süreç hemen bitmez: önce kendi temizliğini yapar. Temizlik süresi süreç başına 0 ile 39 saniye arasındadır.
- SY18.
killkomutunun çıkış kodu her denemede 0’dır; sinyal iletildi demektir. - SY19. Beklemeden verilen tanı şudur: “komut döndü, hedefler bitti.” Yanlış tanı sayısı, o anda gerçekte bitmemiş hedeflerin sayısıdır.
- SY20. Zorlayan sinyal bütün hedefleri bitirir; isteği kabul edip temizliği süren süreçlerin temizliği yarıda kesilir.
- SY21. İkinci tohum 20260219’dur.
# --- ortak tanim, birinci dersteki bicimiyle TOHUM, IKINCI_TOHUM = 20260218, 20260219 KULLANICI = ("kok", "uygulama", "yedek", "izleme") KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici", "kuyruk-isleyici", "onbellek-temizleyici") def uretec(tohum): d = tohum def sonraki(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return sonraki def surecler(tohum=TOHUM, sayi=24): r = uretec(tohum) liste = [] for i in range(sayi): tur = r(10) desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir") liste.append({"pid": 1000 + i * 7 + r(5), "kullanici": KULLANICI[r(len(KULLANICI))], "komut": KOMUT[r(len(KOMUT))], "desen": desen, "oncelik": r(11) - 5, "bellek": 20 + r(400), "sinyal_yok_sayar": r(10) < 2}) return liste # --- bu dersin katmani: sinyal ve temizlik def sinyal_gonder(surecler_, sinyal, hedefler): """Ortak tanim: `sonlandir` yoksayilabilir , `zorla` yoksayilamaz.""" biten, direnen = [], [] for s in surecler_: if s["pid"] not in hedefler: continue if sinyal == "zorla" or not s["sinyal_yok_sayar"]: biten.append(s["pid"]) else: direnen.append(s["pid"]) return {"biten": len(biten), "direnen": len(direnen), "direnen_pid": sorted(direnen)} S = surecler() HEDEF = {s["pid"] for s in S if s["desen"] == "agir"} print("hedef:", len(HEDEF), "agir surec") print("sonlandir:", sinyal_gonder(S, "sonlandir", HEDEF)) print("zorla :", sinyal_gonder(S, "zorla", HEDEF))
hedef: 7 agir surec
sonlandir: {'biten': 2, 'direnen': 5, 'direnen_pid': [1014, 1043, 1092, 1108, 1128]}
zorla : {'biten': 7, 'direnen': 0, 'direnen_pid': []}
Yedi ağır sürecin yalnız 2’si sonlandırma isteğini kabul ediyor, 5’i direniyor.
Zorlayan sinyalde 7’sinin 7’si bitiyor. Direnen süreçlerin listesi çıktıda görünmez —
kill komutu bu bilgiyi vermez, veremez. Bu, kursun ortak tanımının ikinci bağlayıcı
okumasıdır.
Beklemenin Ölçüsü
Yukarıdaki iki satır sinyalin nihai sonucudur. Operatör ise sonucu değil, bir andaki durumu görür. Sonlandırma isteğini kabul eden süreç hemen bitmez; açık dosyalarını kapatır, tamponunu boşaltır, kilidini bırakır. O sırada süreç hâlâ listede durur.
# Onceki blogun uzerine: S, HEDEF, uretec, TOHUM oradan gelir. def temizlik_ata(surecler_, tohum=TOHUM): """Sonlandirma istegini kabul eden surec hemen bitmez: once temizlik yapar.""" r = uretec(tohum) for s in surecler_: s["temizlik"] = r(40) # saniye return surecler_ def sonlandirma_denemesi(surecler_, hedefler, bekleme): """Istek gonderildi , `bekleme` saniye sonra bakildi. `kill` cikis kodu her durumda 0: sinyal ILETILDI demek , hedef BITTI demek degil.""" biten, temizleniyor, yok_sayan = [], [], [] for s in surecler_: if s["pid"] not in hedefler: continue if s["sinyal_yok_sayar"]: yok_sayan.append(s["pid"]) elif s["temizlik"] <= bekleme: biten.append(s["pid"]) else: temizleniyor.append(s["pid"]) return len(biten), len(temizleniyor), len(yok_sayan) temizlik_ata(S) print("hedef:", len(HEDEF), "surec | `kill` cikis kodu her satirda 0") print("bekleme biten temizleniyor yok sayan hayatta yanlis tani") for b in (0, 1, 5, 10, 30, 60): biten, tmz, yok = sonlandirma_denemesi(S, HEDEF, b) print(f"{b:7d} {biten:5d} {tmz:12d} {yok:9d} {tmz + yok:7d}" f" {len(HEDEF) - biten:11d}")
hedef: 7 surec | `kill` cikis kodu her satirda 0
bekleme biten temizleniyor yok sayan hayatta yanlis tani
0 0 2 5 7 7
1 0 2 5 7 7
5 0 2 5 7 7
10 1 1 5 6 6
30 2 0 5 5 5
60 2 0 5 5 5
İlk satır dersin en sert sayısıdır. Komut döndüğü anda hedeflerin hiçbiri bitmemiştir; yanlış tanı 7/7. Beş süreç isteği yok saydı, ikisi de henüz temizliğini bitirmedi. Çıkış kodu yine de 0’dır — komut işini yapmıştır, sinyal iletilmiştir.
İkinci okuma bekleme sütunundadır. Beş saniye beklemek hiçbir şey değiştirmiyor; onuncu saniyede 1, otuzuncu saniyede 2 süreç bitiyor. Otuzdan sonra hiçbir şey değişmiyor: kalan 5 süreç isteği yok sayıyor ve ne kadar beklenirse beklensin bitmeyecek. Beklemek temizliği tamamlar, direnci çözmez. Bu ayrım doğru yordamı belirler.
Doğru sıra dört adımdır: isteği gönder, bekle, kill -0 ile doğrula, ancak hâlâ
duranı zorla. Servis yöneticileri de bunu yapar ve bekleme süresi birim tanımında ayarlanır
bir değerdir; o taraf bu kursun sonraki konusudur.
Bekleme süresinin seçimi bu tabloya bakılarak yapılır ve iki yönde de bedeli vardır. Kısa seçilirse temizliğini sürdüren süreçler gereksiz yere zorlanır; tabloda beş saniyede zorlamak, onuncu ve otuzuncu saniyede kendiliğinden bitecek iki süreci kesmek demektir. Uzun seçilirse direnen süreçler boşuna beklenir: otuzuncu saniyeden sonra tabloda hiçbir sütun değişmez, altmış saniye beklemek yalnız arızayı uzatır. Ölçülmüş bir eşik yoksa seçilen süre bir varsayım olarak kalır ve o varsayım her iki yönde de yanlış tanı üretir.
Ulaşmayan ve Bekleyen Sinyal
Direnç, sinyalin işe yaramamasının tek nedeni değildir. Üç durum daha vardır ve üçü de aynı görüntüyü üretir: komut 0 döndürür, hedef durur.
Birincisi bekleyen sinyaldir. Durdurulmuş bir sürece gönderilen sonlandırma isteği hemen
işlenmez; süreç kod yürütmediği için sinyal bekler. Önceki dersteki durdurulmuş işler tam
olarak bu durumdadır: istek iletilir, kuyruğa yazılır ve süreç SIGCONT ile sürdürülene kadar
orada kalır. Zorlayan sinyal bu kuralın dışındadır; onu çekirdek uygular ve sürecin kod
yürütmesini beklemez. Bir işi gerçekten durdurmanın taşınabilir yolu bu yüzden önce sürdürüp
sonra istek göndermektir.
İkincisi engellenmiş sinyaldir. Bir süreç kritik bir bölüme girerken belirli sinyalleri geçici olarak engelleyebilir; engel kalkana kadar sinyal bekler. Dışarıdan bakan operatör engellenmiş sinyal ile yok sayılmış sinyali ayırt edemez — ikisinde de hiçbir şey olmaz.
Üçüncüsü yanlış hedeftir. Süreç numaraları yeniden kullanılır: bir süreç bittikten sonra
aynı numara başka bir sürece verilebilir. Numarayı bir dosyadan okuyup gönderen betikler bu
yüzden numarayı doğrulamadan kullanmamalıdır; kill -0 ile varlığı sınamak yeterli değildir,
sınanan şey numaranın kime ait olduğudur.
Bu üç durumun ortak sonucu şudur: sinyal göndermek bir olay değil, bir istektir ve isteğin
sonucu yalnız hedefe bakarak öğrenilir. Bir kapanış yordamının doğru yazılmış olması da
gönderen tarafı ilgilendirir — servislerin yeniden yapılandırılmasında SIGHUP kullanılması
bu yüzden yaygındır: servis yeniden başlatılmadan yapılandırmasını yeniden okur ve açık
bağlantıları düşürmez. Aynı sinyalin başka bir programda varsayılan eylemi sonlandırmaktır;
anlamı sinyalin değil, programın sözleşmesinindir.
Zorlamanın Bedeli
Bekleme adımını atlayıp doğrudan zorlayan sinyali göndermek çekici bir kısayoldur: sonuç kesindir, hedeflerin hepsi biter. Kesinliğin bir bedeli vardır ve o da sayılabilir.
# Onceki bloklarin uzerine: S, HEDEF, sonlandirma_denemesi, sinyal_gonder, # temizlik_ata, surecler, IKINCI_TOHUM. z = sinyal_gonder(S, "zorla", HEDEF) kesilen = [s["pid"] for s in S if s["pid"] in HEDEF and not s["sinyal_yok_sayar"] and s["temizlik"] > 0] print("dogrudan zorlayan sinyal:", z["biten"], "/", len(HEDEF), "bitti") print(" yarida kesilen temizlik:", len(kesilen), "surec") print("dogru sira (istek , bekle , dogrula , zorla):") biten, tmz, yok = sonlandirma_denemesi(S, HEDEF, 30) print(" 30 saniye sonra kendiliginden biten:", biten, "| zorlanmasi gereken:", tmz + yok) print() for tohum in (TOHUM, IKINCI_TOHUM): S2 = temizlik_ata(surecler(tohum), tohum) H2 = {s["pid"] for s in S2 if s["desen"] == "agir"} g = sinyal_gonder(S2, "sonlandir", H2) b0 = sonlandirma_denemesi(S2, H2, 0)[0] b30 = sonlandirma_denemesi(S2, H2, 30)[0] print(f"tohum {tohum}: hedef {len(H2)} | istegi kabul eden {g['biten']}" f" | 0 sn sonra biten {b0} | 30 sn sonra biten {b30}" f" | yanlis tani {len(H2) - b0}")
dogrudan zorlayan sinyal: 7 / 7 bitti yarida kesilen temizlik: 2 surec dogru sira (istek , bekle , dogrula , zorla): 30 saniye sonra kendiliginden biten: 2 | zorlanmasi gereken: 5 tohum 20260218: hedef 7 | istegi kabul eden 2 | 0 sn sonra biten 0 | 30 sn sonra biten 2 | yanlis tani 7 tohum 20260219: hedef 5 | istegi kabul eden 5 | 0 sn sonra biten 0 | 30 sn sonra biten 4 | yanlis tani 5
Doğrudan zorlamak 7/7 sonuç veriyor, ve 2 sürecin temizliği yarıda kesiliyor. Kesilen
temizlik soyut bir kayıp değildir: tamponu boşaltmamış bir süreç yazdığını sanan veriyi
kaybeder, kilidini bırakmamış bir süreç geride bir kilit dosyası bırakır, geçici dizinini
silmemiş bir süreç onu diskte bırakır. Bu üç sonucun hiçbiri kill çıktısında görünmez ve
üçü de sonraki çalıştırmada başka bir arıza olarak ortaya çıkar.
Bekleyerek yapılan sıralamada aynı iki süreç kendiliğinden bitiyor ve yalnız 5 hedef zorlanıyor. Fark iki süreçlik değildir; iki temiz kapanışlıktır.
İkinci tohumda hedef sayısı 5’e iniyor ve isteği kabul edenlerin sayısı 2 yerine 5 oluyor — kompozisyon tamamen değişiyor. Değişmeyen tek şey ilk sütundur: her iki tohumda da komut döndüğü anda biten hedef sayısı 0’dır ve beklemeden verilen tanı bütün hedeflerde yanlıştır. Kaç sürecin direneceği kurguya bağlıdır; komutun dönmesinin hiçbir şey söylemediği değildir.
Modelin dışında kalan bir sınır da not edilmelidir: zorlayan sinyal burada her hedefi
bitiriyor, ama gerçek bir sistemde çekirdek çağrısının içinde kesilemez uykuda bekleyen bir
süreç ona da yanıt vermez. O durumda süreç D durumunda görünür ve tek çare bekleyişin
nedenini gidermektir.
Özet
- Sinyal veri taşımayan bir kesme bildirimidir; süreç onu yakalayabilir, yok sayabilir ya da
varsayılan eyleme bırakabilir.
SIGKILLveSIGSTOPyakalanamaz, engellenemez. killkomutunun çıkış kodu sinyalin iletildiğini bildirir, hedefin bittiğini değil. Doğrulamanın aracıkill -0’dır.- Yedi ağır hedeften sonlandırma isteğini yalnız 2’si kabul ediyor, 5’i yok sayıyor; zorlayan sinyalde 7/7 bitiyor.
- Komut döndüğü anda biten hedef sayısı 0’dır: yanlış tanı 7/7. Onuncu saniyede 1, otuzuncu saniyede 2 süreç biter; otuzdan sonra hiçbir şey değişmez.
- Doğrudan zorlamak 2 sürecin temizliğini yarıda keser; beklemeli sırada aynı iki süreç temiz kapanır ve yalnız 5 hedef zorlanır. Doğru sıra istek, bekleme, doğrulama, zorlamadır.
Sonraki Adım
Bu ders süreci durdurmayı ölçtü. Durdurmak her zaman doğru yanıt değildir: ağır bir süreç gerekli bir iş yapıyor olabilir ve istenen şey onu bitirmek değil, yavaşlatmaktır. Sonraki ders öncelik değerini ele alır ve tek bir soruyu sayar: bir sürecin önceliğini değiştirmenin gerçekten görülebilir etkisi ne kadardır, ve değişen sütun ile değişen davranış aynı şey midir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.