---
title: 'İptal ve Zaman Aşımı'
source: 'https://academia.sh/tr/kurslar/rust-eszamanlilik/iptal-ve-zaman-asimi'
course: 'Eşzamanlılık ve Asenkron Rust'
language: tr
updated: '2026-09-13T05:09:28+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir görevin bırakılmasıyla kurulan iptali, bir daha yoklanmama durumu olarak tanımlar'
    - 'Zaman aşımını süre yerine tükenen bir yoklama bütçesiyle modelleyip bütçesi biten görevin nasıl bırakıldığını gösterir'
    - 'Kursun on dersini kapanış tablosunda birleştirip her birimin ilerleme koşulunu kaynak metinden doğrular'
---

# İptal ve Zaman Aşımı

Kursun kapanış dersi bir görevin bırakılmasıyla kurulan iptali ölçüyor: bırakılan görev bir daha yoklanmaz ve hiç sınıfına düşer; zaman aşımı da bir süre değil, tükenen bir yoklama bütçesiyle modellenir.

Eşzamansız Girdi/Çıktı dersi kaynakta yazılı ama hiç tamamlanmayan bir görevin sorusunu açık
bıraktı: bir görev sonsuza kadar duraklayabilir, peki ona bir daha hiç dokunulmazsa ne olur?
Bu kursun kapanış dersi bu soruyu ele alıyor. Rust'ın eşzamansız modelinde bir görevi
durdurmanın ayrı bir çağrısı yok — bir gelecek yalnızca yoklandığı sürece ilerler, bu yüzden
onu bir daha yoklamamak, o görevi iptal etmenin ta kendisi oluyor.

Go'nun Eşzamanlılık kursu iptali bir goroutine'in nasıl duracağını belirleyen dört yoldan
biri, yani bir durma düzeneği olarak ölçtü. Bu ders aynı kavramı başka türlü ölçüyor: iptal
edilen bir görevin kendi başına bir yürütme akışı yok ki dursun — iptal burada bir
**ilerlememe** durumu, kaynakta yazılı kalıp bir daha yoklanmayan bir görevin akıbeti.
Ölçülen iki ayrı yol var: bir görev elle bırakılarak iptal edilebilir, ya da bir yoklama
bütçesi tükendiğinde otomatik olarak bırakılarak zaman aşımına uğrayabilir. İkisi de aynı
sınıfa düşüyor.

## Bırakılan Bir Görev Bir Daha Yoklanmaz

Bir görevin bırakılması tek başına iptal anlamına gelmiyor. Tamamlanmış bir görev de,
ürettiği değer okunduktan sonra bellekte durmaya devam etmiyor — o da bırakılıyor, ama bu
bir temizlik, bir iptal değil. Ayrım, bırakma anında görevin **bitmiş olup olmadığında**:
bitmeden bırakılan bir görev bir daha hiç yoklanmayacak, bitmiş bir görevin zaten yoklanacak
bir şeyi kalmamış durumda. Aşağıdaki çekirdek kesiti bu ayrımı iki alanla tutuyor:
`baslatildi` görevin en az bir kez yoklandığını, `tamamlandi` son değerini üretip
üretmediğini işaretliyor. Yalnızca ilki doğru, ikincisi yanlışken bırakılan bir görev iptal
edilmiş sayılıyor; bu, görevin kendi `Drop` uygulamasında bir kayıt gönderilerek
ölçülüyor.

```rust
// ilerle.rs — cekirdegin kesiti: birakma ile kurulan iptal ve yoklama butcesiyle
// modellenen zaman asimi.

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

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

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

pub 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 yoklandiktan sonra elle birakilabilen gorev: baslamis is olculebilir,
// tamamlanma ise ancak ikinci yoklama gerceklesirse kayda geciyor.
pub struct IptalEdilebilirIs {
    pub ad: &'static str,
    pub baslatildi: bool,
    pub tamamlandi: bool,
    pub kanal: Sender<String>,
}

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

impl Drop for IptalEdilebilirIs {
    fn drop(&mut self) {
        if self.baslatildi && !self.tamamlandi {
            self.kanal.send(format!("{}-birakildi", self.ad)).unwrap();
        }
    }
}

// her yoklamada bir azalan bir sayacla ilerleyen uzun bir is; tamamlanmadan
// birakilirsa kalan miktar sifirdan buyuk kalir.
pub struct UzunIs {
    pub kalan: u32,
    pub ad: &'static str,
    pub kanal: Sender<String>,
}

impl Future for UzunIs {
    type Output = &'static str;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<&'static str> {
        if self.kalan == 0 {
            self.kanal.send(format!("{}-tamamlandi", self.ad)).unwrap();
            Poll::Ready(self.ad)
        } else {
            self.kalan -= 1;
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }
}

impl Drop for UzunIs {
    fn drop(&mut self) {
        if self.kalan > 0 {
            self.kanal.send(format!("{}-yarida-birakildi", self.ad)).unwrap();
        }
    }
}

// ic gorevi sinirli sayida yoklama hakkiyla saran gorev: hak tukenince ic gorev
// hemen birakilir ve bir daha yoklanmaz.
pub struct ZamanAsimliGorev<F: Future> {
    pub ic: Option<Pin<Box<F>>>,
    pub hak: u32,
    pub ad: &'static str,
    pub kanal: Sender<String>,
}

impl<F: Future> Future for ZamanAsimliGorev<F> {
    type Output = Result<F::Output, ()>;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<F::Output, ()>> {
        if self.hak == 0 {
            self.ic = None;
            self.kanal.send(format!("{}-zaman-asimi", self.ad)).unwrap();
            return Poll::Ready(Err(()));
        }
        self.hak -= 1;
        match self.ic.as_mut().unwrap().as_mut().poll(cx) {
            Poll::Ready(x) => Poll::Ready(Ok(x)),
            Poll::Pending => Poll::Pending,
        }
    }
}
```

```rust
// iptal.rs — birakma ile kurulan iptal ve yoklama butcesiyle modellenen zaman asimi
// tek kosumda.
mod ilerle;
use ilerle::{kostur, IptalEdilebilirIs, UzunIs, ZamanAsimliGorev, Uyandirici};
use std::future::Future;
use std::sync::mpsc::channel;
use std::sync::{Arc, Condvar, Mutex};
use std::task::{Context, Waker};

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

    // --- tamamlanan gorev: kostur onu bitene kadar yokluyor ---
    let (sonuc, yoklama) = kostur(IptalEdilebilirIs {
        ad: "gorev-tamamlanan",
        baslatildi: false,
        tamamlandi: false,
        kanal: gonder.clone(),
    });

    // --- iptal edilen gorev: bir kez elle yoklaniyor, sonra birakiliyor ---
    let mut iptal_edilen = Box::pin(IptalEdilebilirIs {
        ad: "gorev-iptal-edilen",
        baslatildi: false,
        tamamlandi: false,
        kanal: gonder.clone(),
    });
    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 _ = iptal_edilen.as_mut().poll(&mut baglam);
    drop(iptal_edilen);

    // --- yoklama butcesiyle zaman asimi: biri butce icinde bitiyor, digeri asiyor ---
    let (sonuc_a, but_yoklama_a) = kostur(ZamanAsimliGorev {
        ic: Some(Box::pin(UzunIs { kalan: 1, ad: "is-a", kanal: gonder.clone() })),
        hak: 3,
        ad: "is-a",
        kanal: gonder.clone(),
    });
    let (sonuc_b, but_yoklama_b) = kostur(ZamanAsimliGorev {
        ic: Some(Box::pin(UzunIs { kalan: 5, ad: "is-b", kanal: gonder.clone() })),
        hak: 2,
        ad: "is-b",
        kanal: gonder.clone(),
    });

    drop(gonder);
    let mut kayitlar: Vec<String> = al.try_iter().collect();
    kayitlar.sort();

    println!("gorev-tamamlanan {} yoklamada bitti, sonuc: {}", yoklama, sonuc);
    println!("gorev-iptal-edilen 1 yoklamadan sonra elle birakildi");
    println!();
    println!("is-a (hak=3, kalan=1) -> {} yoklamada sonuc: {:?}", but_yoklama_a, sonuc_a);
    println!("is-b (hak=2, kalan=5) -> {} yoklamada sonuc: {:?}", but_yoklama_b, sonuc_b);
    println!();
    println!("kayitlar ({}):", kayitlar.len());
    for k in &kayitlar {
        println!("  {}", k);
    }
}
```

```
gorev-tamamlanan 2 yoklamada bitti, sonuc: gorev-tamamlanan
gorev-iptal-edilen 1 yoklamadan sonra elle birakildi

is-a (hak=3, kalan=1) -> 2 yoklamada sonuc: Ok("is-a")
is-b (hak=2, kalan=5) -> 3 yoklamada sonuc: Err(())

kayitlar (7):
  gorev-iptal-edilen-baslatildi
  gorev-iptal-edilen-birakildi
  gorev-tamamlanan-baslatildi
  gorev-tamamlanan-tamamlandi
  is-a-tamamlandi
  is-b-yarida-birakildi
  is-b-zaman-asimi
```

**AS7.** `gorev-tamamlanan` iki yoklamada bitiyor — bir duraklama, bir tamamlanma — ve
`async`/`await` dersinden tanıdık $n+1$ kuralını sürdürüyor. `gorev-iptal-edilen` yalnız bir
kez elle yoklanıyor, `-baslatildi` kaydını gönderiyor, sonra doğrudan bırakılıyor; bu bırakma
`Drop` uygulamasını tetikliyor ve `-birakildi` kaydını gönderiyor. Bu iki kayıt görevin
**başlamış işini** ölçülebilir kılıyor: bir yoklama gerçekleşti, bir temizlik çalıştı. Ama
`gorev-iptal-edilen-tamamlandi` kaydı yedi kayıt arasında hiç yok — çünkü ikinci yoklama hiç
gerçekleşmedi. İptal edilen görev **hiç** sınıfına giriyor: kaynakta yazılı, bir kez
dokunulmuş, ama tamamlanmadan bırakılmış.

## Yoklama Bütçesi Tükenince Zaman Aşımı

Zaman aşımı bu kursta bir süreyle değil, bir sayıyla kuruluyor: yukarıdaki kesitteki
`ZamanAsimliGorev`, sardığı görevi en fazla `hak` kez yoklamaya izin veriyor. Bütçe
tükenmeden görev kendi kendine biterse sonuç `Ok` değeriyle dönüyor; bütçe tükendiğinde
`ZamanAsimliGorev` içindeki görevi hemen bırakıyor — `self.ic` alanına `None` atanıyor — ve
bir daha ona dokunmuyor. Bu, önceki bölümdeki elle bırakma düzeneğinin otomatikleştirilmiş
biçimi: kararı görevin kendisi değil, onu saran bütçe veriyor.

**AS8.** `is-a` üç yoklama hakkıyla kuruldu ve yalnızca ikisini kullandı, `Ok("is-a")` ile
bitti. `is-b` yalnızca iki yoklama hakkıyla kuruldu ama beş yoklama gerektiriyordu; üçüncü
çağrıda bütçe sıfıra düştüğü için sarmalayıcı içteki görevi bırakıyor ve `Err(())`
döndürüyor. İçteki görevin kendi `Drop` uygulaması `-yarida-birakildi` kaydını gönderiyor,
çünkü bırakıldığı anda hâlâ üç birimlik işi kalmıştı — beş birimlik işin ikisi tamamlanmış,
üçü **başlamış ama bitmemiş** durumda kalmıştı. `is-b-tamamlandi` kaydı da yedi kayıt
arasında hiç yok. `is-a` **yoklanınca** sınıfına giriyor; `is-b` bütçesi tükendiğinde **hiç**
sınıfına düşüyor — elle bırakılan görevle aynı akıbeti, farklı bir tetikleyiciyle
paylaşıyor.

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

Bırakma, görevin **iç durumunu** göstermiyor. `Drop` uygulaması yalnızca yazması için elle
kodlanmış olanı kaydediyor — `IptalEdilebilirIs` `baslatildi` ile `tamamlandi` bayraklarını,
`UzunIs` kalan sayaç değerini tutuyor. Bu, dilin genel bir "ne kadar iş yapıldı" bilgisini
kendiliğinden açığa çıkarmadığı anlamına geliyor: bir görev türünün yazarı bu bilgiyi
ölçülebilir kılmazsa, bırakılan bir değerin ne durumda olduğu kaynak kod dışında bilinemez.

Yoklama bütçesi de bir süre değil. `hak` alanı kaç kez yoklanacağının bir üst sınırı, ama bir
görevin gerçek dünyada ne kadar sürdüğüyle hiçbir ilişkisi yok — aynı bütçe, her yoklaması
ağır bir görevle de, her yoklaması anlık bir görevle de aynı sayıda yoklama sonra tükeniyor.
Gerçek bir zaman aşımı düzeneği bu sayıyı bir saatle eşleştirir; bu kurs saat kullanmadığı
için, zaman aşımı burada yalnızca **kaç kez denendiğinin** bir ölçüsü, ne kadar beklendiğinin
değil.

## Kapanış Tablosu

| Ders | Ölçülen birim | İlerleme koşulu | Sınırlayıcı ölçüm |
|---|---|---|---|
| İş Parçacığı Oluşturma | İş parçacığı başlatma ve birleştirme | kendi başına · başkası bitince | Kayıtların sırası ölçülmez, yalnız beklenen sayı var mı ölçülür |
| Kanallarla Mesajlaşma | Kanaldan geçen iletinin sahipliği ve alımı | kendi başına · başkası bitince | Bekleyen taraf süresiz bekler; eksik kayıt beklenen-gelen farkıyla ölçülür |
| İş Parçacıkları Arası Güvenliğin Tipteki Karşılığı | Sınırı geçebilen `Arc<Mutex<...>>` değeri | kendi başına · başkası bitince | Tipin izni veri yarışını engeller, sıraya bağlı doğruluğu garanti etmez |
| Muteks ve Okuma/Yazma Kilidi | Kilit bekleyen taraf | kendi başına · başkası bitince | İki bekleyenden hangisi önce girer ölçülmez, kilit yalnız veriyi korur |
| Atomik İşlemler ve Bellek Sıralaması | Kilitsiz atomik sayaç | kendi başına | Atomik olmak sıralı olmak değildir; hangi artış önce ölçülmez |
| Gelecekler (futures) | Yoklanan ve hiç yoklanmayan görev | yoklanınca · hiç | Yoklanmayan görev hata değildir, sessizce iz bırakmaz |
| `async`/`await` | Duraklama noktası ve yoklama sayısı | yoklanınca · başkası bitince | Duraklama sayısı ölçülür, ne kadar duraklayacağı ölçülmez |
| Yürütücüler | Aynı görev, iki yürütücü kurgusu | yoklanınca | Yürütücü ne zaman yoklayacağına karışır, görevin gövdesine karışmaz |
| Eşzamansız Girdi/Çıktı | Modellenmiş girdi/çıktı kaynağı | yoklanınca · başkası bitince | Modellenen bekleme gerçek gecikmeyi göstermez, ölçülen yoklama sayısı |
| İptal ve Zaman Aşımı | Bırakılan ve zaman aşımına uğrayan görev | hiç | Bırakma iç durumu göstermez; bütçe keyfi bir yoklama sınırıdır |

## Özet

- Bir görevi bırakmak, Rust'ın eşzamansız modelindeki iptal çağrısıdır; bırakılan görev bir
  daha yoklanmaz ve **hiç** sınıfına düşer.
- Bir bırakma yalnızca görev tamamlanmadan önce gerçekleşirse iptaldir; tamamlanmış bir
  görevin bırakılması sıradan bir temizliktir — iki durum bu derste ayrı kayıtlarla ayrıştı.
- Zaman aşımı bir süre değil bir yoklama bütçesiyle modellendi: bütçesi tükenen görev hemen
  bırakıldı ve bir daha yoklanmadı — o da **hiç** sınıfına düştü.
- İptal edilen görevlerin başlamış işi ölçülebilir kaldı — başladığını ve bırakıldığını
  gösteren kayıtlar vardı — ama tamamlandığını gösteren kayıt hiçbir zaman gelmedi.
- Go'nun Eşzamanlılık kursu iptali bir durma düzeneği olarak ölçtü; bu ders aynı kavramı bir
  ilerlememe durumu olarak ölçtü.
- Kapanış tablosu, kursun on dersini ve dört sınıfını (kendi başına, yoklanınca, başkası
  bitince, hiç) tek bir bakışta topladı.

## Kurs Kapanışı

Bu kurs on ders boyunca tek bir soruyu sürdürdü: bir birim ilerlemek için neye ihtiyaç
duyuyor. Yanıt hep aynı dört isimden biriydi ve kapanış tablosu bu dört ismin on farklı
birimde nasıl dağıldığını gösterdi — iş parçacıkları kendi başlarına ya da birbirlerini
bekleyerek ilerledi, kilitler ve kanallar bu bekleyişi taşıdı, gelecekler yalnız
yoklandıklarında ilerledi ve bu son ders bir görevin hiç ilerlemeyebileceğini — kaynakta
yazılı kalıp bir daha dokunulmayarak — gösterdi. Bu, deponun beşinci ve şimdilik son
eşzamanlılık kursuydu; beş kurs birlikte aynı alanı beş farklı soruyla dolaştı.

Sıradaki kurs, Rust Ekosistemi ve İleri Konular, dilin eşzamanlılık dışındaki geri kalanına
bakıyor: makrolar, derleyici güvenliğinin gönüllü olarak dışına çıkılan kod kesimleri, başka
dillerle kurulan çağrı arayüzleri ve bir Rust projesinin paket yönetiminden yayınına kadarki
yaşam döngüsü. Bu derste ölçülen ilerleme sorusu — bir birimin ilerlemek için neye ihtiyaç
duyduğu — orada yeniden sorulmuyor; sıradaki kurs kendi ölçü eksenini kendi konusundan
kuracak.
