---
title: 'Yarış Koşulları'
source: 'https://academia.sh/tr/kurslar/guvenli-kodlama/yaris-kosullari'
course: 'Güvenli Kodlama'
language: tr
updated: '2026-08-17T18:06:42+00:00'
license: 'CC BY-SA 4.0'
---

# Yarış Koşulları

Aynı kontrolün eşzamanlı isteklerde kaç kez geçtiğinin ölçülmesi: tek kullanımlık bir kotada on altı eşzamanlı istek denetimsiz kurulumda on altı kez geçer, kilit ve tek yazarlı kuyruk bunu kotaya indirir, yeniden denemesiz atomik koşullu güncelleme kota üçken yalnız bir isteği geçirerek iki meşru isteği reddeder; yedi kontrol noktasının dördü korumasızdır ve sekiz eşzamanlı istekte yirmi yedi fazla geçiş üretir, tek yazarlı kuyruk bunu sıfıra indirir ve sekizinci nokta eklendiğinde dağıtık kurulumda fazla geçiş otuz dörde çıkar.

Önceki dersin bütün ölçümü tek bir varsayıma dayanıyordu: adımlar birbiri ardına çalışıyor.
Durum makinesi ödeme adımına geldiğinde durumu okuyor, kararı veriyor ve durumu
güncelliyordu. Okuma ile yazma arasında geçen sürede başka hiçbir şeyin olmadığı
varsayılıyordu.

İki istek aynı anda geldiğinde bu varsayım düşer. İkisi de durumu `onaylandi` okuyabilir,
ikisi de kararı geçebilir ve ikisi de yazabilir. Kural kodda yazılıdır, denetim çalışır ve
sonuç yine yanlıştır. **Yarış koşulu** budur: kusur denetimin varlığında değil, denetim ile
etkinin arasındaki boşluktadır.

## Üç Adımın Arasına Girmek

Paylaşılan bir değeri değiştiren her istek üç adımdır: oku, denetle, yaz. Bu üçlünün
arasına başka bir isteğin girmesi, ikinci isteğin birincinin henüz yazmadığı değeri okuması
demektir. İki istek de eski değere bakarak karar verir ve iki karar da olumlu çıkar.

Aşağıdaki ölçüm bir **modeldir**: gerçek bir sunucu, gerçek bir istemci ve gerçek bir ağ
yoktur. Zamanlama gerçek değildir; istekler adım adım serpiştirilerek kendi yazdığımız
düzenleyicide koşar, bu yüzden çıktı her koşumda aynıdır. Bir servise eşzamanlı istek
göndererek kural atlatmayı denemek **yazılı yetki ve tanımlı kapsam olmadan hem yasadışı hem
meslek dışıdır**; ölçülen şey burada kendi modelimizin davranışıdır.

```js
// yaris/model.mjs — eszamanli istek modeli (model): gercek bir sunucu, gercek bir istemci ve
// gercek bir ag yok. Zamanlama gercek degil, adim adim serpistirmeyle uretilir; bu yuzden
// cikti her kosumda aynidir.

// KH17: her istek uc adimdir — paylasilan durumu oku, karar ver, yaz. Yaris kosulu bu ucun
// arasina baska bir istegin girmesiyle dogar.
export function* istek(ad, durum, kurulum) {
  const yerel = durum.kalan;                     // 1. oku
  yield "oku";
  const gecti = yerel > 0;                       // 2. denetle
  yield "denetle";
  if (!gecti) return { ad, sonuc: "reddedildi" };
  if (kurulum === "kuyruk") return { ad, sonuc: "kuyrukta" };
  if (kurulum === "atomik" && durum.kalan !== yerel) return { ad, sonuc: "carpisma" };
  durum.kalan = yerel - 1;                       // 3. yaz
  return { ad, sonuc: "gecti" };
}

// KH18: dort kurulum ayni istek kumesini kosar. "denetimsiz" her istegi adim adim serpistirir;
// "kilit" oku-denetle-yaz ucluslunu serilestirir; "atomik" yazmadan once degeri yeniden sinar;
// "kuyruk" yazmayi tek yazarli bir kuyruga birakir ve kuyruk yeniden denetler.
export function kosu(eszamanli, kurulum, kota = 1) {
  const durum = { kalan: kota }, sonuc = [];
  const uretec = Array.from({ length: eszamanli },
    (_, i) => istek(`i-${i + 1}`, durum, kurulum));
  if (kurulum === "kilit") {
    for (const u of uretec) { let r; while (!(r = u.next()).done); sonuc.push(r.value); }
  } else {
    const acik = uretec.map((u) => ({ u, bitti: false }));
    while (acik.some((a) => !a.bitti))
      for (const a of acik) {
        if (a.bitti) continue;
        const r = a.u.next();
        if (r.done) { a.bitti = true; sonuc.push(r.value); }
      }
  }
  if (kurulum === "kuyruk")
    for (const s of sonuc)
      if (s.sonuc === "kuyrukta")
        s.sonuc = durum.kalan > 0 ? (durum.kalan--, "gecti") : "reddedildi";
  const gecen = sonuc.filter((s) => s.sonuc === "gecti").length;
  return { gecen, fazla: Math.max(0, gecen - kota), kalan: durum.kalan };
}

// KH19: kontrol noktasi, paylasilan bir degeri okuyup denetleyip yazan her yerdir.
export const NOKTA = [
  { ad: "indirim-kodu-kullan", kota: 1, kurulum: "denetimsiz" },
  { ad: "iade-ode",            kota: 1, kurulum: "denetimsiz" },
  { ad: "kota-dus",            kota: 3, kurulum: "kilit" },
  { ad: "abone-devri-onay",    kota: 1, kurulum: "kilit" },
  { ad: "is-emri-atama",       kota: 1, kurulum: "denetimsiz" },
  { ad: "fatura-kilitle",      kota: 1, kurulum: "atomik" },
  { ad: "sayac-okuma-al",      kota: 2, kurulum: "denetimsiz" },
];
```

```js
// yaris/olcum.mjs — ayni kontrol kac kez geciyor, kilit ve tek yazarli kuyruk kacini kapatiyor.
import { kosu, NOKTA } from "./model.mjs";
const yaz = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const KURULUM = ["denetimsiz", "kilit", "atomik", "kuyruk"];

const A = [-11, 13, 8, 9, 9];
console.log("1. tek kullanimlik indirim kodu (kota 1): kac istek kontrolden gecti");
yaz(A, "eszamanli", ...KURULUM);
for (const n of [1, 2, 4, 8, 16]) yaz(A, n, ...KURULUM.map((k) => kosu(n, k).gecen));

const B = [-11, 13, 8, 9, 9];
console.log("\n2. ayni olcum kota 3 ile (gecmesi gereken en cok 3 istek)");
yaz(B, "eszamanli", ...KURULUM);
for (const n of [1, 2, 4, 8, 16]) yaz(B, n, ...KURULUM.map((k) => kosu(n, k, 3).gecen));

// KH20: fazla gecen istek, kotanin ustunde gecen istek sayisidir; olculen sey budur.
const ESZAMANLI = 8;
const C = [-22, 7, 13, 9, 9, 11];
console.log(`\n3. ${NOKTA.length} kontrol noktasi, her birinde ${ESZAMANLI} eszamanli istek`);
yaz(C, "kontrol noktasi", "kota", "kurulum", "gecen", "fazla", "kuyrukta");
let fazlaToplam = 0, kuyrukToplam = 0;
for (const n of NOKTA) {
  const s = kosu(ESZAMANLI, n.kurulum, n.kota), k = kosu(ESZAMANLI, "kuyruk", n.kota);
  fazlaToplam += s.fazla; kuyrukToplam += k.fazla;
  yaz(C, n.ad, n.kota, n.kurulum, s.gecen, s.fazla, k.fazla);
}
yaz(C, "toplam", "", "", "", fazlaToplam, kuyrukToplam);

// 4. kapsama: yeni kontrol noktasi eklendiginde
const YENI = { ad: "odeme-plani-olustur", kota: 1, kurulum: "denetimsiz" };
const genis = [...NOKTA, YENI];
const fazla = (kume, merkezi) => kume.reduce((t, n) =>
  t + kosu(ESZAMANLI, merkezi ? "kuyruk" : n.kurulum, n.kota).fazla, 0);
const D = [-36, 8, 12, 14, 13];
console.log("\n4. kapsama: korumasiz kontrol noktasi ve fazla gecen istek");
yaz(D, "kume", "nokta", "korumasiz", "fazla gecen", "disarida %");
for (const [ad, k, merkezi] of [
  ["bugunku dagitik durum", NOKTA, false],
  ["tek yazarli kuyruk butun noktalarda", NOKTA, true],
  ["yeni nokta eklendi, dagitik", genis, false],
  ["yeni nokta eklendi, merkezi kalip", genis, true],
]) {
  const acik = merkezi ? 0 : k.filter((n) => n.kurulum === "denetimsiz").length;
  yaz(D, ad, k.length, acik, fazla(k, merkezi), ((acik / k.length) * 100).toFixed(1));
}
```

```
1. tek kullanimlik indirim kodu (kota 1): kac istek kontrolden gecti
eszamanli     denetimsiz   kilit   atomik   kuyruk
1                      1       1        1        1
2                      2       1        1        1
4                      4       1        1        1
8                      8       1        1        1
16                    16       1        1        1

2. ayni olcum kota 3 ile (gecmesi gereken en cok 3 istek)
eszamanli     denetimsiz   kilit   atomik   kuyruk
1                      1       1        1        1
2                      2       2        1        2
4                      4       3        1        3
8                      8       3        1        3
16                    16       3        1        3

3. 7 kontrol noktasi, her birinde 8 eszamanli istek
kontrol noktasi          kota      kurulum    gecen    fazla   kuyrukta
indirim-kodu-kullan         1   denetimsiz        8        7          0
iade-ode                    1   denetimsiz        8        7          0
kota-dus                    3        kilit        3        0          0
abone-devri-onay            1        kilit        1        0          0
is-emri-atama               1   denetimsiz        8        7          0
fatura-kilitle              1       atomik        1        0          0
sayac-okuma-al              2   denetimsiz        8        6          0
toplam                                                    27          0

4. kapsama: korumasiz kontrol noktasi ve fazla gecen istek
kume                                   nokta   korumasiz   fazla gecen   disarida %
bugunku dagitik durum                      7           4            27         57.1
tek yazarli kuyruk butun noktalarda        7           0             0          0.0
yeni nokta eklendi, dagitik                8           5            34         62.5
yeni nokta eklendi, merkezi kalip          8           0             0          0.0
```

Sayılar **ölçüm** sınıfındadır; girdileri KH17–KH20'dir.

## Kontrol Eşzamanlılık Kadar Geçiyor

Birinci tablo tek kullanımlık bir indirim kodunu ölçüyor: kota 1, yani en çok bir istek
geçmelidir. Denetimsiz kurulumda geçen istek sayısı eşzamanlı istek sayısına eşit — 2 istek
2 kez, 16 istek 16 kez geçiyor. Kontrol her istekte gerçekten çalıştı ve her istekte olumlu
sonuç verdi, çünkü hepsi yazmadan önce okudu.

Bu, denetimin **etkisiz** olduğu anlamına gelmez; ölçeklenmediği anlamına gelir. Tek istekle
koşulan bir sınama bu kusuru hiçbir zaman göremez: birinci satırda dört kurulum da 1 veriyor.
Kusur ancak eşzamanlılık bir değişken olduğunda görünür.

Kilit ve tek yazarlı kuyruk her eşzamanlılık düzeyinde 1 veriyor. İkisi aynı sonuca iki
farklı yoldan varıyor: kilit oku–denetle–yaz üçlüsünü serileştirir, kuyruk okumayı serbest
bırakıp yalnız yazmayı tek yazara toplar ve yazma anında yeniden denetler. Kuyruğun ayırt
edici özelliği, yavaş okumaların kilit tutmamasıdır.

Kilidin de bir bedeli vardır ve o bedel bu ölçümde görünmez. Kilit, kritik bölümü
serileştirdiği için eşzamanlılık arttıkça bekleyen istek sayısını artırır; kritik bölümün
içinde bir okuma yavaşsa bütün istekler o okumayı sırayla bekler. Tablodaki `gecen` sütunu
bu bekleme süresini ölçmez, yalnız doğruluğu ölçer. İki sütunun ayrı tutulması gerekir:
doğruluk sütununda kilit ile kuyruk aynı sonucu verir, gecikme sütununda vermez.

## Savunmanın Bedeli: Çarpışma

İkinci tablo aynı ölçümü kota 3 ile yineliyor ve bir savunmanın bedelini açığa çıkarıyor.
Denetimsiz kurulum yine eşzamanlılık kadar geçiriyor; kilit ve kuyruk 3'te duruyor. Atomik
koşullu güncelleme ise **1** veriyor.

Sebep modeldeki gerçekleştirimdir: yazma anında değer değişmişse istek çarpışma sayılıp
reddediliyor ve **yeniden denenmiyor**. Kota 3 iken üç isteğin geçmesi gerekirken yalnız
biri geçiyor; iki meşru istek kaybediliyor. Koşullu güncelleme fazla geçişi engelliyor ama
yeniden deneme olmadan kullanıldığında meşru işin bir bölümünü de durduruyor.

Bu, bu müfredatın kuralının bir örneğidir: bedeli yazılmayan savunma ölçülmemiş sayılır.
Koşullu güncellemenin doğru biçimi çarpışan isteği belirli bir sınıra kadar yeniden
denemektir; sınır da bir karardır ve yükün altında kaç isteğin düşeceğini belirler.

İkinci tablonun kota 1 satırlarıyla kota 3 satırları arasındaki fark da bir uyarıdır. Kota 1
iken atomik kurulum doğru sonucu verir ve kusur görünmez; kusur ancak kota 1'in üstüne
çıktığında ortaya çıkar. Bir savunmanın tek bir yapılandırmada doğru davranması, bütün
yapılandırmalarda doğru davrandığı anlamına gelmiyor. Ölçüm kümesinin en az iki kota
değeri içermesi gerekir.

## Yedi Noktada Yirmi Yedi Fazla Geçiş

Üçüncü tablo ölçümü tek bir koddan kod tabanına taşır. Yedi kontrol noktası var; her biri
paylaşılan bir değeri okuyup denetleyip yazıyor. Dördü korumasız, ikisi kilitli, biri atomik.

Her noktada sekiz eşzamanlı istek koşuyor ve **fazla geçen** istek sayısı yazılıyor: kotanın
üstünde geçen istek. Korumasız dört nokta sırasıyla 7, 7, 7 ve 6 fazla geçiş üretiyor;
toplam **27**. Korumalı üç nokta 0 üretiyor.

Sayılar arasındaki fark kotadan gelir. `sayac-okuma-al` noktasının kotası 2 olduğu için sekiz
istekten altısı fazladır; kotası 1 olan noktalarda yedisi. Fazla geçiş sayısı bu yüzden nokta
sayısıyla değil, **kota ile eşzamanlılığın farkıyla** ölçülür. "Dört noktamız korumasız"
cümlesi 27 sayısını vermez.

Son sütun aynı noktaların tek yazarlı kuyrukla koşulduğunda ne verdiğini gösteriyor: yedi
noktanın yedisinde 0. Kapatma tek bir yerdedir; her nokta için ayrı bir kilit tasarlanmadı.

Korumalı üç noktanın hangileri olduğu da anlamlıdır. `kota-dus` ve `abone-devri-onay`
kilitlidir, çünkü ikisi de para ya da abonelik durumu değiştiren, üzerinde uzun düşünülmüş
noktalardır. Korumasız dördü ise bir sayaç düşüren, bir kayıt işaretleyen ya da bir atama
yapan noktalardır; hiçbiri "kritik" görünmez. Yarış koşullarının bulunduğu yer, kritik
sayılan nokta değil, **paylaşılan bir değeri okuyup yazan** noktadır. Envanterin ölçütü de
bu olmalıdır: kritiklik değil, paylaşılan yazma.

## Kapsama ve Sekizinci Nokta

Dördüncü tablo kapsamayı yazar. Bugünkü dağıtık durumda yedi noktanın dördü korumasız —
dışarıda kalan oran **%57,1** — ve toplam fazla geçiş 27. Bütün yazmalar tek yazarlı
kuyruktan geçtiğinde korumasız nokta 0, fazla geçiş 0.

Sekizinci bir nokta — `odeme-plani-olustur` — dağıtık kurulumda korumasız eklenirse fazla
geçiş 27'den **34**'e, dışarıda kalan oran %62,5'e çıkar. Merkezî kalıpta aynı nokta hiçbir
fazla geçiş üretmez; yazma yolu zaten kuyruktan geçer.

Fark burada da kalıbın gücünde değil, yazmanın **tek bir yoldan** yapılmasındadır. Dağıtık
kurulumda her yeni kontrol noktası için "bu değeri kim daha yazıyor" sorusunun yeniden
sorulması gerekir; kuyrukta soru bir kez sorulmuştur. Eşzamanlılık, kod incelemesinde en zor
görülen kusur sınıfıdır: kod tek başına okunduğunda doğrudur ve yalnız iki kopyası aynı anda
koştuğunda yanlıştır.

Bu yüzden ölçümün kendisi bir sınama biçimidir. Yukarıdaki düzenleyici gerçek zamanlama
kullanmadığı için sonucu her koşumda aynıdır; aynı serpiştirme her kontrol noktasına
uygulanabilir ve fazla geçiş sayısı bir sayı olarak kaydedilebilir. Gerçek zamanlamaya
bırakılan bir sınama ise bazen geçer bazen kalır ve geçtiğinde hiçbir şey kanıtlamaz. Bir
yarış koşulunun varlığı, kendi yazdığımız serpiştirmede gösterilebiliyorsa gösterilmiş
sayılır; gösterilemiyorsa yokluğu değil, o serpiştirmede görünmediği bilinir.

## Özet

- Yarış koşulu denetimin yokluğunda değil, denetim ile etkinin arasındaki boşlukta doğar;
  oku–denetle–yaz üçlüsünün arasına giren ikinci istek eski değeri okur.
- Tek kullanımlık bir kotada denetimsiz kurulum eşzamanlılık kadar geçiş üretir: 16 eşzamanlı
  istek 16 kez geçer. Tek istekle koşulan sınama bu kusuru hiçbir zaman göremez.
- Kilit ve tek yazarlı kuyruk her düzeyde kotayı korur; kuyruğun ayırt edici yanı okumaların
  kilit tutmamasıdır.
- Yeniden denemesiz atomik koşullu güncelleme kota 3 iken yalnız 1 isteği geçirir; fazla
  geçişi kapatırken iki meşru isteği de reddeder. Bedeli yazılmayan savunma ölçülmemiştir.
- Yedi kontrol noktasının dördü korumasız; sekiz eşzamanlı istekte toplam 27 fazla geçiş
  üretiyorlar. Fazla geçiş sayısı nokta sayısıyla değil, kota ile eşzamanlılığın farkıyla
  ölçülür.
- Tek yazarlı kuyruk fazla geçişi 0'a indirir; sekizinci korumasız nokta eklendiğinde dağıtık
  kurulumda fazla geçiş 34'e çıkarken merkezî kalıpta 0 kalır.

## Sonraki Adım

Bu konu beş derste tek bir soruyu ölçtü: kimin ne yapabildiği kodun kaç noktasında
denetleniyor, kaç nokta dışarıda kalıyor. Kimlik doğrulama noktalarında sızdırılan bilgi
sayıldı, oturum akışlarında yenilenmeyen kimlik ve yaşamaya devam eden oturum sayıldı, yetki
matrisinde nesne düzeyinde denetimi olmayan uç ve yanlış geçen istek sayıldı, akış sırasında
kural dışı yol sayıldı ve bu derste eşzamanlı isteklerin ürettiği fazla geçiş sayıldı. Beş
ölçümün beşinde de aynı biçim çıktı: dağıtık savunma her kümede dışarıda nokta bıraktı,
merkezî kalıp aynı kümede sıfır verdi ve her kümeye yeni bir kalem eklendiğinde dağıtık
tarafın dışarıda bıraktığı arttı, kalıbınki değişmedi.

Bütün bu denetimlerin dayandığı bir şey ise hiç ele alınmadı. Kimlik doğrulama bir değeri
karşılaştırdı, oturum kimliği bir yerden üretildi, yetki ölçütü bir imzaya ya da bir kayda
güvendi, kuyruk bir kimlikle çalıştı. Bu değerlerin nasıl üretildiği, ne kadar tahmin
edilebilir oldukları ve kod tabanının neresinde durdukları sorulmadı — **anahtarlar ve
sırlar** hâlâ kodun içinde bir yerde duruyor. Sonraki konu, **Kriptografi ve Sırlar**, bu
soruyu aynı kapsama ölçüsüyle ele alır: kaç sır var, kaçı kod tabanının dışında, kaçı depo
geçmişinde kalmış.
