---
title: 'İş Parçacığı Oluşturma'
source: 'https://academia.sh/tr/kurslar/rust-eszamanlilik/is-parcacigi-olusturma'
course: 'Eşzamanlılık ve Asenkron Rust'
language: tr
updated: '2026-10-21T05:03:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir birimin kendi başına, başkası bitince ya da hiç ilerlememe durumlarını birbirinden ayırt eder'
    - 'Ölçüm çekirdeğini koşturarak on üç birimin dört sınıfa nasıl dağıldığını doğrular'
    - 'Bu kursun ölçü eksenini önceki eşzamanlılık kurslarının eksenlerinden ayırır'
---

# İş Parçacığı Oluşturma

Kursun açılış dersi ölçüm çekirdeğini tam koşturur: on üç birimin 5'i kendi başına, 3'ü yoklanınca, 3'ü başkası bitince ilerledi, 2'si hiç ilerlemedi; iş parçacığı başlatma ve birleştirme bu dağılımın kendi başına ve başkası bitince sınıflarını kuruyor.

Trait'ler, Genellikler ve Hata Yönetimi kursu on beş ders boyunca kaynakta yazılan bir gövdenin
kaç kez koştuğunu ölçtü ve kapanışında bu soruyu bırakmadığını, yönünü değiştireceğini
söyledi. O kapanış cümlesi sıradaki sorunun "hangi iş parçacığının koşturduğu" olacağını
öngörmüştü — ama bu, JVM, Eşzamanlılık ve Başarım kursunun kendi sorusudur ve orada zaten
yanıtlandı. Bu kurs başka bir soru soruyor. Bir iş, kaynakta yazılı olsa bile, ilerlemek için
bir şeye ihtiyaç duyabilir: bir yoklayıcıya, başka bir birimin bitmesine, ya da hiçbir şeye.
Kurs boyunca sorulan tek soru şu: **bu iş ilerlemek için neye ihtiyaç duyuyor?**

Bu, deponun beşinci eşzamanlılık kursudur. Önceki dördü aynı alanı farklı sorularla dolaştı:
İşletim Sistemi Kavramları kursu kaç ayrı serpiştirmenin mümkün olduğunu saydı, Python'ın
Eşzamanlılık ve Başarım kursu bir tik modelinde hangi adımların örtüştüğünü ölçtü, JVM,
Eşzamanlılık ve Başarım kursu bir adımı hangi iş parçacığının koşturduğunu izledi, Go'nun
Eşzamanlılık kursu bir goroutine'in nasıl duracağını sınıflandırdı. Bu kurs hiçbirinin adını
yeniden kullanmıyor: kilit, kanal, iş parçacığı, veri yarışı ve zamanlayıcı kavramları zaten
kuruldu ve burada yeniden tanımlanmıyor. İlgili bir kavrama değinilecekse önce hangi kursta
kurulduğu adıyla anılacak, orada ne ölçüldüğü tek cümleyle söylenecek, sonra bu kursun kendi
sorusuna dönülecek.

## Dört Sınıf

Sorunun dört yanıtı var ve kurs boyunca bu dört ad değişmiyor.

| Sınıf | Tanım |
|---|---|
| kendi başına | Başlatıldıktan sonra kimseye ihtiyacı yok, kendi ilerliyor |
| yoklanınca | Kendiliğinden ilerlemiyor; bir yoklayıcı onu ilerletiyor |
| başkası bitince | Bir başka birimin bitmesini bekliyor |
| hiç | Kaynakta yazılı, ama hiç ilerlemedi |

Bu dörtlü JVM, Eşzamanlılık ve Başarım kursunun sınıflandırmasıyla karışmamalı: orada ölçülen
bir adımı **hangi** iş parçacığının koşturduğuydu, burada ölçülen bir birimin ilerlemek için
**neye ihtiyaç duyduğu**. Go'nun Eşzamanlılık kursuyla da karışmamalı: orada ölçülen bir
birimin nasıl **duracağı**ydı (bitiş), burada ölçülen nasıl **ilerleyeceği** (başlangıç ve
devam). İşletim Sistemi Kavramları kursunun serpiştirme sayımı ve Python'ın Eşzamanlılık ve
Başarım kursunun tik modeli de bu dörtlüyle karışmıyor: ikisi de bir adımın **ne zaman**
çalıştığını sayıyordu, bu kurs ise bir birimin ilerlemesi için **ne** gerektiğini soruyor —
zaman bilgisi hiçbir yerde ölçülmüyor. Bu dersin konusu kendi başına ve başkası bitince
sınıfları: bir iş parçacığı başlatıldığında kendi başına mı ilerliyor, yoksa onu birleştirmek
için bekleyen taraf başkası bitince mi ilerliyor.

## İş Parçacığı Başlatma ve Birleştirme

İşletim Sistemi Kavramları kursu bir iş parçacığının ne olduğunu ve zamanlayıcının onu nasıl
çalıştırdığını kurdu; bu kurs o kavramı yeniden anlatmıyor. Rust'ta bir iş parçacığı
başlatmak, bir kapanışı ayrı bir yürütme biriminin çalıştıracağı biçimde teslim etmektir.
Başlatma çağrısı bir tutamaç döndürür; bu tutamaç üzerinde birleştirme çağrıldığında, çağıran
taraf o iş parçacığının bitmesini bekler ve iş parçacığının döndürdüğü değere erişir.

Bu iki işlemin ilerleme koşulları farklıdır. Başlatılan iş parçacığının kendisi, çalışmaya
başladığı andan itibaren kimseye ihtiyaç duymaz — zamanlayıcı ona bir işlemci payı verdiği
sürece kendi başına ilerler. Buna karşılık birleştirme çağrısını yapan taraf, o iş parçacığı
bitene kadar ilerleyemez; bu, başkası bitince sınıfının en doğrudan örneğidir. Aynı ayrım,
sinyal bekleyen bir iş parçacığı için de geçerli: bir kanaldan haber beklemek, birleştirme
çağırmaktan farklı bir düzenektir ama aynı sınıfa girer, çünkü ikisi de kendi dışında bir
olayın gerçekleşmesini bekler.

Birleştirme çağrısının kendisi bir değer döndürür: başlatılan kapanışın döndürdüğü değer,
tutamaç üzerinden geri gelir. Bu, Sahiplik ve Bellek Modeli kursunda kurulan taşıma
kuralının doğrudan bir uzantısıdır — kapanışın yakaladığı her değer o iş parçacığına
taşınıyor, kapanış kendi ürettiği değeri döndürdüğünde bu değer de birleştirme çağrısına
taşınıyor. Çağıran taraf o değere birleştirme bitmeden erişemez; erişebilseydi, iş parçacığı
henüz üretmemiş olabileceği bir değeri okumaya çalışırdı. Birleştirmenin başkası bitince
sınıfına girmesi bu yüzden bir uygulama ayrıntısı değil, sahiplik kuralının zorunlu
sonucudur.

## `hiç` Sınıfı: Kaynakta Yazılı, Hiç Çalışmadı

İki birim bu koşumda hiç ilerlemedi ve ikisi de kaynakta gayet açık biçimde duruyor.
Birincisi bir kapanış: `_hic_baslatilmayan` adıyla bağlanıyor, rapor kanalına bir kayıt
göndermek üzere yazılıyor, ama hiçbir yerde çağrılmıyor ya da bir iş parçacığına teslim
edilmiyor. Rust'ta bir kapanış, çağrılmadığı sürece yalnızca bir değerdir — içindeki gövde
derlenir, ama koşum sırasında bir kez bile tetiklenmez. İkincisi bir görev:
`gorev-hic-yoklanmayan` adlı `BirKezDuraklar` değeri kuruluyor, ama `kostur` işlevine hiç
verilmiyor; bir gelecek de, kapanış gibi, yoklanmadığı sürece yalnızca bellekte duran bir
değerdir.

Bu ikisinin ortak noktası, kaynaktaki varlıklarının koşumdaki etkileriyle aynı şey olmaması.
`siniflar` dizisindeki on üç satırın hepsi kaynakta yazılı; rapor tablosundaki "kayit var mi"
sütunu yalnızca ikisi için "hayir" diyor. Bu, kaynak kodunun ölü kod içerdiği anlamına
gelmez — aynı kapanış türü ya da aynı görev türü başka bir koşumda çağrılabilir ya da
yoklanabilirdi. Ölçülen, kaynağın taşıdığı olasılık değil, bu belirli koşumda hangi yolun
seçildiği.

## Ölçüm Çekirdeği

Kursun geri kalanında kesitleri alınacak çekirdek `ilerle.rs`dir. On üç ayrı birimi tek
koşumda başlatır, sınıflandırır ve bir kanal üzerinden gelen kayıtları toplar. Kayıtlar bir
karma yapıya değil sıradan bir listeye yazılıyor ve okunmadan önce sıralanıyor — hangi iş
parçacığının hangi sırayla kaydını gönderdiği bu kursta hiçbir yerde ölçülmüyor ve
basılmıyor, yalnızca kaydın var olup olmadığı ölçülüyor.

```rust
// ilerle.rs — bir is ilerlemek icin neye ihtiyac duyuyor: kimseye mi, bir yoklayiciya mi,
// bir baskasinin bitmesine mi, yoksa hic ilerlemiyor mu.

use std::future::Future;
use std::pin::Pin;
use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, Condvar, Mutex};
use std::task::{Context, Poll, Wake, Waker};
use std::thread;

// --- elle yazilan yurutucu: standart kitaplikta yurutucu yoktur ---

struct Uyandirici {
    hazir: Mutex<bool>,
    kosul: Condvar,
}

impl Wake for Uyandirici {
    fn wake(self: Arc<Self>) {
        *self.hazir.lock().unwrap() = true;
        self.kosul.notify_one();
    }
}

fn kostur<F: Future>(gorev: F) -> (F::Output, u32) {
    let mut gorev = Box::pin(gorev);
    let u = Arc::new(Uyandirici {
        hazir: Mutex::new(false),
        kosul: Condvar::new(),
    });
    let waker: Waker = u.clone().into();
    let mut baglam = Context::from_waker(&waker);
    let mut yoklama = 0;
    loop {
        yoklama += 1;
        match gorev.as_mut().poll(&mut baglam) {
            Poll::Ready(x) => return (x, yoklama),
            Poll::Pending => {
                let mut h = u.hazir.lock().unwrap();
                while !*h {
                    h = u.kosul.wait(h).unwrap();
                }
                *h = false;
            }
        }
    }
}

// --- bir kez duraklayip devam eden gorev ---

struct BirKezDuraklar {
    duraklandi: bool,
    ad: &'static str,
    kanal: Sender<String>,
}

impl Future for BirKezDuraklar {
    type Output = &'static str;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<&'static str> {
        if self.duraklandi {
            self.kanal.send(self.ad.to_string()).unwrap();
            Poll::Ready(self.ad)
        } else {
            self.duraklandi = true;
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }
}

struct HemenHazir {
    ad: &'static str,
    kanal: Sender<String>,
}

impl Future for HemenHazir {
    type Output = &'static str;
    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<&'static str> {
        self.kanal.send(self.ad.to_string()).unwrap();
        Poll::Ready(self.ad)
    }
}

async fn once_icini_bekle(ic: BirKezDuraklar, kanal: Sender<String>) -> &'static str {
    let _ = ic.await;
    kanal.send(String::from("gorev-await-eden")).unwrap();
    "await-eden"
}

fn main() {
    let (gonder, al) = channel::<String>();

    // --- kendi basina ilerleyenler: baslatildiktan sonra kimseye ihtiyaclari yok ---
    for i in 1..=3 {
        let g = gonder.clone();
        thread::spawn(move || {
            g.send(format!("iplik-kendi-basina-{}", i)).unwrap();
        });
    }

    // --- baskasinin bitmesini bekleyenler ---

    // (a) ana is parcacigi birlestirmeyi bekliyor
    let g = gonder.clone();
    let tutamac = thread::spawn(move || {
        g.send(String::from("iplik-birlestirilen")).unwrap();
    });
    tutamac.join().unwrap();
    gonder.send(String::from("ana-birlestirme-sonrasi")).unwrap();

    // (b) bir is parcacigi kanaldan haber bekliyor
    let (isaret_gonder, isaret_al) = channel::<()>();
    let g = gonder.clone();
    let bekleyen = thread::spawn(move || {
        isaret_al.recv().unwrap();
        g.send(String::from("iplik-kanal-bekleyen")).unwrap();
    });
    let g = gonder.clone();
    thread::spawn(move || {
        g.send(String::from("iplik-isaret-veren")).unwrap();
        isaret_gonder.send(()).unwrap();
    });
    bekleyen.join().unwrap();

    // --- hic baslatilmayan ---
    let g = gonder.clone();
    let _hic_baslatilmayan = move || {
        g.send(String::from("hic-baslatilmayan")).unwrap();
    };

    // --- yoklaninca ilerleyenler ---
    let (_, yoklama_a) = kostur(BirKezDuraklar {
        duraklandi: false,
        ad: "gorev-yoklanan-a",
        kanal: gonder.clone(),
    });
    let (_, yoklama_b) = kostur(HemenHazir {
        ad: "gorev-hazir-b",
        kanal: gonder.clone(),
    });

    // --- await eden: icteki bitmeden ilerlemiyor ---
    let ic = BirKezDuraklar {
        duraklandi: false,
        ad: "gorev-ic",
        kanal: gonder.clone(),
    };
    let (_, yoklama_c) = kostur(once_icini_bekle(ic, gonder.clone()));

    // --- hic yoklanmayan gorev ---
    let _hic_yoklanmayan = BirKezDuraklar {
        duraklandi: false,
        ad: "gorev-hic-yoklanmayan",
        kanal: gonder.clone(),
    };

    // --- rapor: beklenen sayida kayit okunur ve siralanir ---
    let beklenen = 3 + 2 + 2 + 2 + 2; // kendi basina 3, birlestirme 2, kanal 2, yoklanan 2, await 2
    let mut kayitlar: Vec<String> = Vec::new();
    for _ in 0..beklenen {
        kayitlar.push(al.recv().unwrap());
    }
    kayitlar.sort();

    println!("kaydedilen ilerlemeler ({}):", kayitlar.len());
    for k in &kayitlar {
        println!("  {}", k);
    }

    println!();
    println!("yoklama sayilari: a={} b={} await={}", yoklama_a, yoklama_b, yoklama_c);

    let siniflar: [(&str, &str); 13] = [
        ("iplik-kendi-basina-1", "kendi basina"),
        ("iplik-kendi-basina-2", "kendi basina"),
        ("iplik-kendi-basina-3", "kendi basina"),
        ("iplik-isaret-veren", "kendi basina"),
        ("iplik-birlestirilen", "kendi basina"),
        ("ana-birlestirme-sonrasi", "baskasi bitince"),
        ("iplik-kanal-bekleyen", "baskasi bitince"),
        ("gorev-await-eden", "baskasi bitince"),
        ("gorev-yoklanan-a", "yoklaninca"),
        ("gorev-hazir-b", "yoklaninca"),
        ("gorev-ic", "yoklaninca"),
        ("hic-baslatilmayan", "hic"),
        ("gorev-hic-yoklanmayan", "hic"),
    ];

    println!();
    println!("{:<26}{:<18}{}", "birim", "sinif", "kayit var mi");
    for (ad, sinif) in siniflar {
        let var = kayitlar.iter().any(|k| k == ad);
        println!("{:<26}{:<18}{}", ad, sinif, if var { "evet" } else { "hayir" });
    }

    println!();
    for s in ["kendi basina", "yoklaninca", "baskasi bitince", "hic"] {
        let adet = siniflar.iter().filter(|(_, k)| *k == s).count();
        println!("{:<18}{}", s, adet);
    }
    println!("toplam birim: {}", siniflar.len());
}
```

```
kaydedilen ilerlemeler (11):
  ana-birlestirme-sonrasi
  gorev-await-eden
  gorev-hazir-b
  gorev-ic
  gorev-yoklanan-a
  iplik-birlestirilen
  iplik-isaret-veren
  iplik-kanal-bekleyen
  iplik-kendi-basina-1
  iplik-kendi-basina-2
  iplik-kendi-basina-3

yoklama sayilari: a=2 b=1 await=2

birim                     sinif             kayit var mi
iplik-kendi-basina-1      kendi basina      evet
iplik-kendi-basina-2      kendi basina      evet
iplik-kendi-basina-3      kendi basina      evet
iplik-isaret-veren        kendi basina      evet
iplik-birlestirilen       kendi basina      evet
ana-birlestirme-sonrasi   baskasi bitince   evet
iplik-kanal-bekleyen      baskasi bitince   evet
gorev-await-eden          baskasi bitince   evet
gorev-yoklanan-a          yoklaninca        evet
gorev-hazir-b             yoklaninca        evet
gorev-ic                  yoklaninca        evet
hic-baslatilmayan         hic               hayir
gorev-hic-yoklanmayan     hic               hayir

kendi basina      5
yoklaninca        3
baskasi bitince   3
hic               2
toplam birim: 13
```

**IP1.** Bu koşum belirlenimcidir: beş ayrı koşumda aynı on üç birim, aynı sıralı listede ve
aynı sınıf dağılımıyla üretildiği doğrulandı. **On üç birimin 5'i kendi başına, 3'ü
yoklanınca, 3'ü başkası bitince ilerledi; 2'si hiç ilerlemedi.** Bu sayı kursun geri kalanında
değişmiyor; her ders yalnız kendi kesitini alıyor.

Beş `kendi başına` satırının üçü döngüyle başlatılan bağımsız iş parçacıkları, biri sinyal
gönderen iş parçacığı, biri de birleştirilmeyi bekleyen tarafın başlattığı iş parçacığının
kendisi. Bu beşinin ortak noktası, başlatıldıkları andan kayıtlarını gönderdikleri ana kadar
kimseden bir şey beklememeleri. Üç `başkası bitince` satırından ikisi iş parçacığı düzeyinde:
ana iş parçacığı birleştirme çağrısı bitene kadar, sinyal bekleyen iş parçacığı da kanaldan
bir haber gelene kadar ilerleyemiyor. Üçüncüsü, `gorev-await-eden`, bu dersin konusu değil —
o bir eşzamansız görevin dış katmanı ve Eşzamansız Programlama konusunda ele alınacak. Üç
`yoklanınca` satırı da aynı konuya ait: bu ders yalnız onların da kaynakta bulunduğunu ve
rapor tablosunda kayıtlarının göründüğünü not ediyor, yoklama düzeneğinin kendisini
açıklamıyor.

## Sınırlayıcı Ölçüm

Kayıtların **sırası** bu derste hiçbir yerde ölçülmüyor: üç bağımsız iş parçacığı hangi
sırayla kaydını gönderirse göndersin, rapor onları önce topluyor, sonra sıralıyor, ancak
ondan sonra yazdırıyor. Bunun nedeni bir eksiklik değil, bilinçli bir sınır: zamanlayıcının
üç iş parçacığını hangi sırayla çalıştıracağı ortama bağlıdır ve bu kurs ortama bağlı hiçbir
değeri basmıyor. Ölçülen şey, beklenen sayıda kaydın **var olup olmadığı** — kaç tane
geldiği ve hangi isimlerin geldiği — sırası değil.

Bu sınır, çekirdeğin `beklenen` sabitinde de görünür: rapor tam olarak on bir kayıt bekliyor
ve o kadarını okuyor, ne bir fazlasını ne bir eksiğini. Eğer bir iş parçacığı kaydını hiç
göndermeseydi, program o kaydı sonsuza kadar beklerdi — bu yüzden `hiç` sınıfına giren iki
birim (`hic-baslatilmayan` kapanışı ve `gorev-hic-yoklanmayan` görevi) rapor kanalına hiç
dokunmuyor; onların kaydı olmayışı `beklenen` sayısının dışında tutularak, yani program
onları hiç beklemeyerek ölçülüyor.

Bu tasarım kararının kendisi bir öğreti taşıyor: bir programın kaç birim beklemesi gerektiği,
koşum sırasında keşfedilen bir şey değil, kaynakta önceden bilinen bir sayıdır. `beklenen`
üç iş parçacığın kendi başlattığı üç kaydını, birleştirme çiftinin iki kaydını, kanal
çiftinin iki kaydını, iki yoklanan görevin iki kaydını ve bekleyen görevin iki kaydını topluyor
— toplamda on bir. Bu toplam elle hesaplanmış bir sabittir, koşumdan öğrenilmiş bir değer
değil; kurs boyunca kullanılacak yöntem budur: beklenen sayı önce kaynaktan çıkarılır, sonra
koşumun o sayıyı karşılayıp karşılamadığına bakılır.

## Özet

- Kursun ölçü ekseni bir birimin ilerlemek için neye ihtiyaç duyduğudur; dört sınıf kurs
  boyunca değişmez: kendi başına, yoklanınca, başkası bitince, hiç.
- Ölçüm çekirdeği on üç birimi sınıflandırıyor: 5'i kendi başına, 3'ü yoklanınca, 3'ü başkası
  bitince ilerledi, 2'si hiç ilerlemedi; bu sayı kurs boyunca değişmiyor.
- Başlatılan bir iş parçacığı, çalışmaya başladığı andan itibaren kendi başına ilerler; onu
  birleştirmek için bekleyen taraf başkası bitince ilerler.
- Kayıtların gönderilme sırası ölçülmez ve basılmaz; ölçülen, beklenen sayıda kaydın var
  olup olmadığıdır.
- JVM, Eşzamanlılık ve Başarım kursu bir adımı hangi iş parçacığının koşturduğunu ölçtü, bu
  kurs aynı adımın ilerlemek için neye ihtiyaç duyduğunu ölçüyor.

## Sonraki Adım

Sinyal bekleyen iş parçacığı bu derste bir işaret kanalıyla ilerledi; sıradaki ders aynı
düzeneği bir yükle çalıştırıyor. Bir kanaldan sahipliğiyle birlikte gelen bir değer, onu
gönderen tarafı kendi başına bırakırken alan tarafı başkası bitince bekletiyor — sıradaki
ders bu ikiliyi bir mesajlaşma örneğiyle ölçüyor.
