---
title: 'Ön Plan ve Arka Plan İşleri'
source: 'https://academia.sh/tr/kurslar/sistem-yonetimi/on-plan-ve-arka-plan-isleri'
course: 'Sistem Yönetimi'
language: tr
updated: '2026-08-17T18:10:04+00:00'
license: 'CC BY-SA 4.0'
---

# Ön Plan ve Arka Plan İşleri

Oturum kapandığında kabuğun 13 işinden `&` ile arka plana alınanların tamamı ölüyor, disown edilenlerin 9'u ölüyor, nohup ve ayrı oturum 13'ünü de yaşatıyor; `jobs` 13 satır gösterirken gerçekte ilerleyen iş sayısı 8.

Önceki ders süreçlere makinenin dışından baktı: hangileri var, hangileri ağır. Süreçlerin bir
de operatörle kurdukları bağ vardır. Bir betik bir uçterminden başlatıldığında yalnız bir
süreç doğmaz; o süreç bir **süreç öbeğine**, öbek bir **oturuma**, oturum bir **denetleyen
uçtermine** bağlanır. Uçtermin kapandığında bu zincir boyunca olaylar yürür.

Kabuk Programlama kursu iş denetimini kullanım düzeyinde kurmuştu: `&`, `wait`, çıkış kodu.
Bu ders o tarafı tekrarlamaz. Ölçtüğü şey tek bir sorudur: **oturum kapandığında hangi
süreçler hayatta kalır** ve `jobs` çıktısı bunu ne kadar önceden söyler.

## Oturum, Öbek ve Denetleyen Uçtermin

Boru hattındaki komutlar tek bir **süreç öbeğine** konur; kabuk sinyalleri öbek başına
gönderir, tek tek süreçlere değil. Bir uçterminden açılan kabuk ve onun bütün çocukları aynı
**oturumu** paylaşır, oturumun başında kabuk durur ve o uçtermin oturumun **denetleyen
uçterminidir**. Bu üç kimlik listelenebilir:

```text
$ ps -eo pid,ppid,pgid,sid,tty,stat,comm
    PID    PPID    PGID     SID TTY      STAT COMMAND
   1000     998    1000    1000 pts/4    Ss   bash
   1014    1000    1014    1000 pts/4    R    rapor-uretici
   1021    1000    1014    1000 pts/4    R    olcum-toplayici
   1043    1000    1043    1000 pts/4    T    yedek-gorevi
   1092       1    1092    1092 ?        Ss   kuyruk-isleyici
```

Bu döküm **örnektir ve çalıştırılmamıştır.** Okunacak üç şey var. İlk iki süreç aynı `PGID`
değerini taşıyor: bir boru hattının iki ucu. Son sürecin `SID` değeri kendi süreç numarasına
eşit ve `TTY` sütunu boş — o süreç **ayrı bir oturumdadır** ve hiçbir uçtermine bağlı
değildir. Üçüncü sürecin durumu `T`: **durdurulmuş.**

Uçtermin kapandığında iki ayrı olay yürür ve ikisi de öldürebilir. Birincisi **kapanma
sinyalidir**: çekirdek onu oturumun başına iletir, kabuk da kendi işlerine yayar. İkincisi
daha sessizdir — uçtermin yok olduğu için ona yazmaya çalışan süreç bir **girdi/çıktı hatası**
alır ve çoğu program bu hatada durur. İkinci olay hiçbir sinyal kaydı bırakmaz.

- **SY8.** Kurgu sunucunun 24 sürecinin bir bölümü operatörün kabuğundan başlatılmıştır;
  gerisi başka oturumlara aittir.
- **SY9.** Her sürecin iki ek özelliği vardır: çıktısı hâlâ uçtermine gidiyor mu (`yazar`) ve
  uçterminden girdi bekliyor mu (`okur`).
- **SY10.** Beş ayrılma yöntemi ölçülür: **ön plan**, **arka plan** (`&`), **disown**,
  **nohup** ve **ayrı oturum**.
- **SY11.** Bir yöntem üç şeyi belirler: süreç oturumda mı, kabuk ona kapanma sinyali
  gönderir mi, süreç o sinyali yok sayar mı. Yönlendirme yapan yöntemler `yazar` özelliğini
  de kapatır.
- **SY12.** Hayatta kalma kuralı: oturum dışındaki süreçlere hiçbir olay ulaşmaz; oturum
  içindekiler önce sinyalle, sonra yazma hatasıyla elenir.
- **SY13.** Yaygın beklenti şudur: ön plandaki iş ölür, öteki dört yöntemin hepsi işi
  yaşatır. Yanlış tanı, bu beklenti ile gerçeğin ayrıldığı süreç sayısıdır.
- **SY14.** İkinci tohum **20260219**'dur.

```python
# --- ortak tanim, birinci dersteki bicimiyle: kurgu sunucu ve kahin
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: oturum bagi
YONTEM = ("on plan", "arka plan", "disown", "nohup", "ayri oturum")


def oturum_dagit(surecler_, tohum=TOHUM):
    """Kabugun kendi isleri makinenin geri kalanindan ayrilir.
    `yazar`: ciktisi hala uctermine gidiyor. `okur`: ucterminden girdi bekliyor."""
    r = uretec(tohum)
    for s in surecler_:
        s["kabuk_isi"] = r(10) < 5
        s["yazar"] = r(10) < 6
        s["okur"] = r(10) < 3
    return surecler_


def uygula(surec, yontem):
    """Bir yontem, surecin uc ozelligini belirler. Kalani surecin kendisinden gelir."""
    oturumda = yontem != "ayri oturum"
    kabuk_gonderir = yontem in ("on plan", "arka plan")
    korumali = yontem in ("nohup", "ayri oturum")
    return {"oturumda": oturumda, "kabuk_gonderir": kabuk_gonderir,
            "yok_sayar": korumali or surec["sinyal_yok_sayar"],
            "yazar": surec["yazar"] and not korumali}


def hayatta_mi(d):
    """Ucterminin kapanmasi IKI ayri olay uretir , ikisi de oldurebilir."""
    if not d["oturumda"]:
        return True                          # oturum disinda: hicbiri ulasmaz
    if d["kabuk_gonderir"] and not d["yok_sayar"]:
        return False                         # birinci olay: kapanma sinyali
    if d["yazar"]:
        return False                         # ikinci olay: uctermin gidince yazma hatasi
    return True


S = oturum_dagit(surecler())
KABUK = [s for s in S if s["kabuk_isi"]]
print("toplam surec:", len(S), "| kabugun isi:", len(KABUK),
      "| baska oturuma ait:", len(S) - len(KABUK))
print("kabuk isleri: sinyali yok sayan", sum(1 for s in KABUK if s["sinyal_yok_sayar"]),
      "| uctermine yazan", sum(1 for s in KABUK if s["yazar"]),
      "| ucterminden okuyan", sum(1 for s in KABUK if s["okur"]))
```

```
toplam surec: 24 | kabugun isi: 13 | baska oturuma ait: 11
kabuk isleri: sinyali yok sayan 4 | uctermine yazan 9 | ucterminden okuyan 5
```

## İşi Arka Plana Almak

İş denetiminin komutları kabuğun kendi komutlarıdır ve süreç tablosunda görünmezler. `&`
komutu arka planda başlatır, `Ctrl+Z` ön plandaki işi **durdurur**, `bg` durdurulmuş işi arka
planda sürdürür, `fg` ön plana geri getirir. `jobs` kabuğun iş tablosunu listeler:

```text
$ jobs -l
[1]-  1014 Running                 ./rapor-uretici --gun 7 &
[2]+  1043 Stopped                 ./yedek-gorevi --tam
[3]   1021 Running                 ./olcum-toplayici | ./ozet &
```

Bu döküm de **örnektir ve çalıştırılmamıştır.** İşlere `%1`, `%2` gibi belirteçlerle atıf
yapılır; `fg %2` ikinci işi ön plana alır. Köşeli parantez içindeki sayı süreç numarası
değildir — kabuğun kendi sayacıdır ve başka bir kabukta anlamı yoktur.

`jobs` tablosunun iki sınırı vardır ve ikisi de bu dersin ölçtüğü şeyi üretir. Birincisi,
tablo **yalnız bu kabuğun işlerini** taşır: başka bir oturumdan başlatılan ya da servis
yöneticisinin başlattığı hiçbir süreç burada görünmez. İkincisi, tablo **şu andaki bağı**
gösterir, gelecekteki sonucu değil.

Bu iki sınırın pratik sonucu şudur: bir işin oturumdan gerçekten ayrıldığını doğrulamanın yolu
`jobs` değildir. Doğrulama **ikinci bir oturum açıp** süreci orada aramaktır; `ps` çıktısında
`TTY` sütununun boş, `PPID` sütununun `1` olması ayrılmanın kanıtıdır. `jobs` çıktısı bu
soruya hiçbir zaman yanıt veremez, çünkü sorulan şey tam olarak `jobs` çıktısının kapsamı
dışındadır.

Kabuk Programlama kursunda kurulan çıkış kodu sözleşmesi burada da geçerlidir: `wait %1` işin
bitmesini bekler ve onun çıkış kodunu döndürür. Bir iş sinyalle sonlandırıldığında kod
**128 artı sinyal numarası** olur; arka plandaki bir işin sessizce ölüp ölmediği bu koddan
anlaşılır. Kod okunmadan `wait` çağrılmazsa bilgi kaybolur — kabuk kapandığında iş tablosu da
gider.

Süreci oturumdan ayırmanın üç yolu vardır. `disown` işi kabuğun tablosundan siler; kabuk artık
ona kapanma sinyali göndermez. `nohup` komutu süreci kapanma sinyalini yok sayacak biçimde
başlatır ve çıktısını bir dosyaya yönlendirir. `setsid` süreci **yeni bir oturuma** koyar;
oturumun denetleyen uçtermini yoktur, dolayısıyla kapanacak bir uçtermin de yoktur. Üç yöntem
aynı işi yapmaz ve fark ölçülebilir.

## Beş Yöntem, Bir Kapanma

```python
# Onceki blogun uzerine: KABUK, YONTEM, uygula, hayatta_mi oradan gelir.
# Yaygin beklenti: on planda birakilan is olur, otekilerin hepsi yasar.
BEKLENTI = {"on plan": False, "arka plan": True, "disown": True,
            "nohup": True, "ayri oturum": True}

print("yontem       uygulanan  beklenen  gercekte  olen  yanlis tani")
for y in YONTEM:
    gercek = {s["pid"] for s in KABUK if hayatta_mi(uygula(s, y))}
    beklenen = {s["pid"] for s in KABUK} if BEKLENTI[y] else set()
    print(f"  {y:11s} {len(KABUK):9d}  {len(beklenen):8d}  {len(gercek):8d}"
          f"  {len(KABUK) - len(gercek):4d}  {len(beklenen ^ gercek):11d}")
print("kahin: her satirda `gercekte` sutunu , kurguyu biz urettik")
```

```
yontem       uygulanan  beklenen  gercekte  olen  yanlis tani
  on plan            13         0         0    13            0
  arka plan          13        13         0    13           13
  disown             13        13         4     9            9
  nohup              13        13        13     0            0
  ayri oturum        13        13        13     0            0
kahin: her satirda `gercekte` sutunu , kurguyu biz urettik
```

İkinci satır bu dersin ana sonucudur. **`&` hiçbir şey yaşatmıyor:** arka plana alınan 13 işin
13'ü de ölüyor, yanlış tanı **13**. Ampersan işi arka plana alır, oturumdan çıkarmaz; kabuk
kapanma sinyalini kendi işlerine yayarken arka plandakileri de kapsar. "Arkasına `&` koydum,
çıkışta sürer" cümlesi kurgudaki her iş için yanlıştır.

Üçüncü satır daha ince bir sonuç verir. `disown` kapanma sinyalini gerçekten engelliyor — ama
13 işten yalnız **4'ü** hayatta kalıyor, **9'u** ölüyor. Ölenler ikinci olayın kurbanıdır:
çıktıları hâlâ uçtermine gidiyordu ve uçtermin yok olunca ilk yazma denemesinde durdular.
`disown` **sinyali keser, akışı kesmez.** Bu, iki ayrı olayı tek bir önlemle karşılamaya
çalışmanın bedelidir.

Son iki satırda yanlış tanı sıfırdır. `nohup` iki olayı birden karşılar: sinyali yok saydırır
**ve** çıktıyı dosyaya yönlendirir. Ayrı oturum ise sorunu ortadan kaldırır; kapanacak bir bağ
yoktur. Kalıcı işler için doğru düzen budur — ya ayrı bir oturum, ya da işi hiç kabuktan
başlatmayıp bir servis birimi hâline getirmek. İkincisi bu kursun sonraki konusudur.

Kabuklar arasında ayrıntı değişebilir; bazı kabuklarda kapanma sinyalinin işlere yayılması bir
seçenekle denetlenir. Ölçülen şey **yaygın davranıştır**, ve yaygın davranışta `&` tek başına
bir koruma değildir.

## Listede Duran, İlerlemeyen İş

Ayrılma sorununun bir eşi vardır. Arka plandaki bir süreç **uçterminden okumaya** kalkarsa
çekirdek onu durdurur; süreç ölmez, bekler. Durdurulmuş süreç `ps` çıktısında `T` durumuyla,
`jobs` çıktısında "Stopped" olarak görünür. İkisi de sürecin var olduğunu doğrular; hiçbiri
ilerleme olmadığını söylemez.

```python
# Onceki bloklarin uzerine: KABUK, uygula, hayatta_mi, oturum_dagit, surecler.
duran = [s for s in KABUK if s["okur"]]
print("arka plana alinan is icinde ucterminden okumaya calisan:", len(duran))
print("  bunlar DURDURULUR: `jobs` listeler , `ps` gosterir , ilerleme sifirdir")
print("  `jobs` satiri:", len(KABUK), "| gercekte ilerleyen:", len(KABUK) - len(duran),
      "| yanlis tani:", len(duran))
print()
for tohum in (TOHUM, IKINCI_TOHUM):
    S2 = oturum_dagit(surecler(tohum), tohum)
    K2 = [s for s in S2 if s["kabuk_isi"]]
    d = {y: len({s["pid"] for s in K2} ^ {s["pid"] for s in K2
                                          if hayatta_mi(uygula(s, y))})
         for y in ("arka plan", "disown", "nohup")}
    print(f"tohum {tohum}: kabuk isi {len(K2):2d} | yanlis tani {d}"
          f" | duran {sum(1 for s in K2 if s['okur'])}")
```

```
arka plana alinan is icinde ucterminden okumaya calisan: 5
  bunlar DURDURULUR: `jobs` listeler , `ps` gosterir , ilerleme sifirdir
  `jobs` satiri: 13 | gercekte ilerleyen: 8 | yanlis tani: 5

tohum 20260218: kabuk isi 13 | yanlis tani {'arka plan': 13, 'disown': 9, 'nohup': 0} | duran 5
tohum 20260219: kabuk isi 11 | yanlis tani {'arka plan': 11, 'disown': 6, 'nohup': 0} | duran 2
```

`jobs` **13 satır** gösteriyor, gerçekte ilerleyen iş **8**. Beş iş bir parola ya da onay
bekliyor ve kimse onlara yazamıyor; listede varlar, ilerlemede yoklar. Yanlış tanı **5**.
Bunun pratik karşılığı, arka plana alınacak her işin girdisinin de kapatılmasıdır — çıktı
yönlendirmesi tek başına yetmez. Girdisi boş bir dosyaya bağlanan bir süreç durdurulmaz;
okuma denemesi hemen dosya sonu döndürür ve süreç kendi hata yolundan ilerler. Durmanın
kendisi de görünür bir olay değildir: iş tablosundaki durum alanı dışında hiçbir yere yazılmaz.

İkinci tohumda kabuğun işi 11'e, duran iş 2'ye iniyor; `&` için yanlış tanı yine **bütün
işler**, `disown` için 9 yerine **6**, `nohup` için yine **0**. Sayılar kurguya bağlıdır;
**sıralama ve yön değişmiyor** — `&` en kötü, `disown` yarım koruma, `nohup` ve ayrı oturum
tam koruma.

## Öksüz ve Zombi Süreçler

Oturum kapandığında hayatta kalan süreçlerin ana süreci ölmüştür. Çekirdek bunları
**öksüz** bırakmaz: ana süreç numaralarını yeniden bağlar ve `ps` çıktısında `PPID` sütunu
`1` olur. Öksüzlük bir arıza değildir; ayrılma yöntemlerinin üçü de bu yolla çalışır.

Asıl karışıklığı yaratan durum bunun tersidir. Bir süreç bittiğinde çıkış kodu, ana süreç onu
**toplayana** kadar süreç tablosunda saklanır. Ana süreç bu toplamayı yapmazsa çocuk **zombi**
durumunda kalır: kodu yürütmüyor, bellek tutmuyor, ama tablo girdisi duruyor. `ps` çıktısında
durumu `Z`, komut adı köşeli parantez içindedir.

Zombiye sinyal göndermenin hiçbir etkisi yoktur — sinyal, kodu yürüten bir sürece iletilir ve
zombi kod yürütmez. Kabuk Programlama kursunda `wait` ile toplanan şey tam olarak budur;
toplamayan bir ana süreç yazıldığında sonuç zombi birikmesidir. Çözüm zombileri sonlandırmak
değil, **ana süreci** düzeltmek ya da sonlandırmaktır; ana süreç gidince zombiler yeniden
bağlanır ve orada toplanırlar.

Birikmenin bedeli sayılabilir bir kaynaktır: her zombi bir süreç tablosu girdisi ve bir süreç
numarası tutar. Yeterince biriktiğinde yeni süreç yaratılamaz. Bu sınırın hangi hata
iletisiyle göründüğü bu konunun beşinci dersinin konusudur.

Kalıcı işler için `nohup` ve `setsid` doğru araçlardır ama tek seçenek değildir. **Uçtermin
çoklayıcı (terminal multiplexer)** sınıfındaki araçlar oturumu kendileri taşır: iş, bağlantı
koptuğunda ölmez, çünkü işin bağlı olduğu uçtermin operatörünkü değil çoklayıcınınkidir.
Aradaki fark ölçüm değil, sahiplik farkıdır — çoklayıcının kendisi kapandığında aynı iki olay
yeniden yürür.

## Özet

- Bir süreç üç kimliğe bağlıdır: süreç öbeği, oturum ve denetleyen uçtermin. Kabuk sinyalleri
  süreç öbeğine gönderir; `ps` çıktısında `PGID`, `SID` ve `TTY` sütunları bu bağı gösterir.
- Uçtermin kapandığında iki ayrı olay yürür: kapanma sinyali ve uçtermine yazmaya çalışan
  sürecin aldığı girdi/çıktı hatası. İkinci olay hiçbir sinyal kaydı bırakmaz.
- `&` oturumdan ayırmaz: arka plana alınan **13 işin 13'ü** ölüyor, yanlış tanı **13**.
- `disown` sinyali keser ama akışı kesmez; 13 işten **4'ü** kalıyor, **9'u** çıktısı uçtermine
  gittiği için ölüyor. `nohup` ve ayrı oturum iki olayı birden karşılar, yanlış tanı **0**.
- `jobs` **13 satır** gösterirken gerçekte ilerleyen iş **8**'dir; uçterminden okumaya çalışan
  5 iş durdurulmuştur ve listede çalışıyor görünür.

## Sonraki Adım

Bu ders bir sinyalin süreçlere nasıl ulaştığını kenardan gördü: kapanma sinyali kabuktan
işlere yayıldı, kimileri onu yok saydı. Yok saymanın kendisi henüz ölçülmedi. Sonraki ders
sinyalleri doğrudan ele alır ve tek bir cümleyi sayar: sonlandırma isteği bir **istektir**,
ve komutun hatasız dönmesi hedefin bittiği anlamına gelmez.
