---
title: 'Atomik Referans Sayımı'
source: 'https://academia.sh/tr/kurslar/sahiplik/atomik-referans-sayimi'
course: 'Sahiplik ve Bellek Modeli'
language: tr
updated: '2026-10-21T05:03:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Aynı sayma kurgusunun Arc ile de kurulduğunda birebir aynı bitiş kaydını ürettiğini koşturarak gösterir'
    - 'Rc ile Arc arasındaki farkın davranışta değil sayacın güncellenme biçiminde olduğunu açıklar'
    - 'Arc üzerinden paylaşılan bir değerin yalnızca okunabildiğini, doğrudan değiştirilemediğini örnekle gösterir'
---

# Atomik Referans Sayımı

Aynı sayma düzeneğinin Arc ile kurulduğunda da birebir aynı bitiş kaydını ürettiği, farkın davranışta değil sayacın nasıl güncellendiğinde olduğu ölçülüyor; hangi bağlamda kullanılabildiği K04'ün konusu olduğu için burada anlatılmıyor. Paylaşılan verinin Arc üzerinden yalnızca okunabildiği, doğrudan değiştirilemediği ayrıca gösteriliyor.

Önceki ders, referans sayımının tek bir bağlamda, sıradan bir tam sayı gibi güncellenen bir
sayaçla çalıştığını, bu sayacın her kopyalamada arttığını ve her bitişte azaldığını ölçtü. Bu
ders aynı sayma işini yapan, ama sayacın kendisini farklı bir biçimde güncelleyen bir türü
ölçüyor: `Arc<T>`. Baştan söylenmesi gereken bir sınır var: bu farkın **hangi bağlamda**
gerekli olduğu — birden çok iş parçacığının aynı değere aynı anda erişmesi — bu dersin konusu
değil, M10/K04'ün konusudur. Burada yalnız şu ölçülüyor: sayaç atomik biçimde güncellendiğinde
davranış değişiyor mu, değişmiyor mu? Ölçülen yine bir değerin bitişi; Eşzamanlılık kursunun
(M09/K03) sorduğu koşan bir birimin nasıl duracağı değil.

Bu sınırın kod üzerindeki karşılığı açıktır: bu derste hiçbir yerde bir iş parçacığı
başlatılmıyor. Aşağıdaki bütün koşumlar, önceki dersteki gibi, tek bir çalışma akışı
içinde baştan sona yürüyor. Bu bir eksiklik değil, bir sınır kararı — `Arc`in adı bir
kullanım bağlamını çağrıştırsa da, bu dersin ölçtüğü şey yalnızca sayacın kendisi,
kullanıldığı ortam değil. Bu, bu konunun daha önce de uyguladığı bir kurala uyuyor: Öbekte
Tekil Sahiplik dersinde bir yazımın neden reddedildiği düzyazıda tarif edilmiş, kabul
edilen yazım koşturulmuştu; burada da bir türün adının çağrıştırdığı bağlam anlatılmıyor,
yalnızca ölçülebilir olan — sayacın kendisi — koşturuluyor.

## Aynı Sayaç, Farklı Güncelleme Biçimi

`Arc`, `Rc` ile aynı arayüzü taşır:

| Rc'deki karşılık | Arc'daki karşılık |
|---|---|
| `Rc::new` | `Arc::new` |
| `Rc::clone` | `Arc::clone` |
| `Rc::strong_count` | `Arc::strong_count` |

Her satırın solu ve sağı, aynı işi yapan iki farklı türün aynı adlı çağrısıdır: bir değeri
öbeğe koyup sayacı bire kurmak, bir kopya üretip sayacı artırmak, sayacın anlık değerini
okumak. Aradaki tek fark, artırma ve azaltma işleminin nasıl gerçekleştirildiğidir. Sıradan
bir artırma üç ayrı adımdan oluşur: mevcut değer okunur, bir eklenir, sonuç geri yazılır.
**Atomik (atomic)** bir artırma bu üç adımı, arada başka bir şeyin araya giremeyeceği tek
bir bölünmez işlem olarak gerçekleştirir. `Rc`nin sayacı sıradan artırma kullanır, `Arc`nin
sayacı atomik artırma kullanır — ama her ikisi de aynı matematiksel sonucu üretir: bir
kopyalamada bir artış, bir bitişte bir azalış. Aynı ayrım azaltma için de geçerlidir: bir
kopyanın bitmesi, sayacı sıradan ya da atomik bir azaltmayla bir indirir; hangi yöntem
kullanılırsa kullanılsın, sayacın son ulaştığı değer aynıdır.

Bu dersin ölçümü, önceki dersteki kurguyu birebir aynı biçimde `Arc` ile yeniden
koşturuyor.

Bu derste ve önceki derste kopya `paylasilan.clone()` değil `Rc::clone(&paylasilan)` ya
da `Arc::clone(&paylasilan)` biçiminde çağrılıyor. İkisi de aynı sonucu üretir — Rust bir
yöntem çağrısını hem `deger.clone()` hem `Tur::clone(&deger)` biçiminde yazmaya izin verir
— ama bu ders boyunca ikinci biçim tercih ediliyor, çünkü ilk biçim okuyana "içeriği
derinlemesine kopyalayan bir işlem" izlenimi verebilir. Oysa burada kopyalanan yalnızca
sayaç ve erişimdir; `Tur::clone(&deger)` yazımı bunu kaynakta daha açık kılıyor.

**PS8.** — "aynı kurgunun `Arc` ile de birebir aynı sayaç dizisini ürettiği" iddiası,
aşağıdaki koşumun `1, 2, 3, 2` sırasıyla basılan sayaç değerleriyle doğrulanıyor — bu,
önceki dersteki `Rc` koşumuyla tıpatıp aynı dizi.

```rust
// atomik_sayac.rs — Arc ayni sayma islemini atomik olarak yapiyor
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    {
        let paylasilan: Arc<Iz> = Arc::new(Iz::yeni("atomik-paylasilan", &defter));
        println!("kurulunca sayac: {}", Arc::strong_count(&paylasilan));

        let ikinci = Arc::clone(&paylasilan);
        println!("bir kopyadan sonra sayac: {}", Arc::strong_count(&paylasilan));

        {
            let _ucuncu = Arc::clone(&paylasilan);
            println!("iki kopyadan sonra sayac: {}", Arc::strong_count(&paylasilan));
        }
        println!("ic kapsam bittikten sonra sayac: {}", Arc::strong_count(&paylasilan));
        println!("ikinci kopya hala okunabilir: {}", ikinci.ad);
    }
    let kayit = defter.borrow();
    println!("defterdeki kayit sayisi: {}", kayit.len());
    println!("kayitlar: {}", kayit.join(", "));
}
```

```
kurulunca sayac: 1
bir kopyadan sonra sayac: 2
iki kopyadan sonra sayac: 3
ic kapsam bittikten sonra sayac: 2
ikinci kopya hala okunabilir: atomik-paylasilan
defterdeki kayit sayisi: 1
kayitlar: atomik-paylasilan
```

Bu koşumdaki `Rc::clone(defter)` çağrısı yalnızca notların tutulduğu `defter`i paylaşmak
için kullanılıyor; ölçülen paylaşım `paylasilan` üzerinde `Arc` ile kuruluyor. Sayaç
sırası — bir, iki, üç, sonra iki — önceki dersle birebir aynı. İç kapsam kapanınca `_ucuncu`
bitiyor, sayaç ikiye dönüyor, ama `Iz` değeri henüz bitmiyor; dış kapsam kapanınca geri kalan
iki kopya da bitiyor ve defterde tek bir kayıt beliriyor. `Arc`, `Rc`nin yaptığı her şeyi
aynı sırayla, aynı sonuçla yapıyor.

Son satırda `ikinci.ad` okunduğunda hâlâ `atomik-paylasilan` metnini veriyor — tıpkı bir
önceki derste `Rc::clone`nun yaptığı gibi, `Arc::clone` da `Iz::yeni`yi yeniden çağırmıyor,
yalnızca aynı değere ikinci bir erişim yolu açıyor. Kopyalamak Veri Kopyalamak Değildir
bölümünde kurulan ayrım burada da geçerli: `Arc::clone`, adındaki fiile rağmen veriyi değil
sayacı ve erişimi çoğaltıyor. Bu koşumda `Iz::yeni` de yalnızca bir kez çağrılıyor;
`ikinci` ve `_ucuncu`, `paylasilan` ile aynı öbek konumundaki aynı değere bakıyor.

## Aynı Kurgu, Aynı Sonuç

İki dersin koşumları yan yana konduğunda fark görünmüyor: sayaç dizisi aynı, defter
uzunluğu aynı, kopyanın bitmesiyle sayacın azalması arasındaki ilişki aynı. Bu, rastlantı
değil — `Arc`, `Rc` ile aynı sözleşmeyi taşıyan bir türdür; ikisi de "sayaç sıfıra inince
değer biter" kuralını uyguluyor. Aralarındaki fark **davranışta değil**, sayacı güncelleyen
işlemin kendisinde: biri sıradan bir artırma/azaltma yapıyor, öbürü bunu atomik olarak
yapıyor. Bu farkın hangi bağlamda anlam kazandığı — birden çok iş parçacığının aynı sayaca
aynı anda erişmesi — burada ele alınmıyor; o soru M10/K04'ün konusu.

Referans Sayımı dersinde ölçülen iki başka özellik de — her değerin kendi sayacının
olması ve bitişin hangi kopyanın değil kaç kopyanın kaldığına bağlı olması — `Arc` için
ayrıca sınanabilir. Aşağıdaki koşum iki bağımsız `Arc` değeri kuruyor, birinin üç kopyasını
kuruluş sırasının dışında bir sırayla bırakıyor ve öbür değerin bundan etkilenmediğini
gösteriyor.

```rust
// arc_ozellikleri.rs — bagimsiz sayaclar ve sira-bagimsizligi Arc icin de gecerli
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;

type Defter = Rc<RefCell<Vec<String>>>;

struct Iz {
    ad: String,
    defter: Defter,
}

impl Iz {
    fn yeni(ad: &str, defter: &Defter) -> Iz {
        Iz {
            ad: ad.to_string(),
            defter: Rc::clone(defter),
        }
    }
}

impl Drop for Iz {
    fn drop(&mut self) {
        self.defter.borrow_mut().push(self.ad.clone());
    }
}

fn main() {
    let defter: Defter = Rc::new(RefCell::new(Vec::new()));
    let birinci: Arc<Iz> = Arc::new(Iz::yeni("birinci-atomik", &defter));
    let ikinci: Arc<Iz> = Arc::new(Iz::yeni("ikinci-atomik", &defter));

    let a = Arc::clone(&birinci);
    let b = Arc::clone(&birinci);
    println!(
        "uc kopyadan sonra birinci sayac: {}, ikinci sayac: {}",
        Arc::strong_count(&birinci),
        Arc::strong_count(&ikinci)
    );

    drop(a);
    drop(birinci);
    println!(
        "iki kopya birakilinca defter (hala bos olmali): {}",
        defter.borrow().join(", ")
    );

    drop(b);
    println!(
        "son kopya da birakilinca defter: {}",
        defter.borrow().join(", ")
    );
    println!("ikinci sayac hala degismedi: {}", Arc::strong_count(&ikinci));

    drop(ikinci);
    let kayit = defter.borrow();
    println!("ikinci de birakilinca defter: {}", kayit.join(", "));
}
```

```
uc kopyadan sonra birinci sayac: 3, ikinci sayac: 1
iki kopya birakilinca defter (hala bos olmali): 
son kopya da birakilinca defter: birinci-atomik
ikinci sayac hala degismedi: 1
ikinci de birakilinca defter: birinci-atomik, ikinci-atomik
```

Üç kopyadan `a` ve orijinal `birinci` bağlaması bırakıldığında defter hâlâ boş — geriye
`b` kaldığı için `birinci-atomik` henüz bitmiyor. `b` da bırakılınca defter doluyor.
Bu sırada `ikinci`nin sayacı hiç değişmiyor: iki değer, iki bağımsız kayıt tutuyor.
Sonuç, Referans Sayımı dersinde `Rc` için görülenle birebir aynı — yalnızca sayacı
güncelleyen işlem farklı. Bırakma sırası burada da `a`, `birinci`, `b` biçiminde, kuruluş
sırasının (`birinci`, sonra `a`, sonra `b`) dışında seçildi; sonuç yine değişmedi, çünkü
belirleyici olan sıradaki kopyanın kimliği değil, geriye kaç kopya kaldığı.

## İki Ayrı Tür, Görünür Bir Seçim

Rust'ın bunu tek bir yapılandırılabilir tür yerine iki ayrı tür — `Rc` ve `Arc` — olarak
sunması bir tasarım kararıdır. Sayacın hangi biçimde güncelleneceği bir çalışma zamanı
bayrağı ya da bir kurulum seçeneği değil, kaynak kodunda **görünür bir tip seçimidir**:
bir değeri `Rc::new` ile mi yoksa `Arc::new` ile mi kurduğunuz, o değeri kimin okuyup
kimin okuyamayacağını değil, sayacının hangi işlemle güncelleneceğini kaynaktan okunur
kılar. Bu, kursun daha önce defalarca gördüğü bir düzenin tekrarıdır: davranış farkı bir
çalışma zamanı kararına değil, bir tip farkına bağlanıyor. İki tür birbirinin yerini
büyük ölçüde tutabilir — aynı `new`, `clone`, `strong_count` çağrılarıyla çalışırlar —
ama hangisinin seçildiği, o değere dair kalıcı bir bilgi olarak kaynakta durur.

Bu düzen, Rust Temelleri kursunun Sıralı ve Küme Yapıları dersinde görülen ayrımla aynı
biçimdedir: karma sözlük ile sıralı sözlük de aynı temel işi görür, ama aralarındaki
seçim bir çalışma zamanı kararı değil, hangi tipin yazıldığına bağlı bir kaynak kararıdır.
`Rc` ile `Arc` arasındaki seçim de aynı kalıba uyuyor — iki tür de "kaç kopya var"
sorusuna aynı yanıtı veriyor, farklı olan yalnızca bu yanıtı üretme biçimi.

## Atomik Sayaç Veriyi Değil Sayacı Korur

Atomik güncelleme yalnızca **sayacı** korur; sayaç değil de paylaşılan verinin kendisi söz
konusu olduğunda `Arc` hiçbir ek güvence vermez. Bir `Arc` üzerinden bir alana doğrudan
yazmaya çalışan bir satır derlenmiyor: `Arc`, tıpkı bir kopyalanmış `Rc` gibi, içerdiği
değere yalnızca paylaşılan bir erişim sağlıyor — bir referansın (`&T`) yalnızca okumaya
izin vermesiyle aynı ilke. Kabul edilen yazım, aynı alanı yalnızca **okuyor**.

Bu kısıt aslında `Arc`e özgü değildir; bir önceki derste `Rc` için de aynı kural
geçerliydi, orada açıkça yazılmamıştı çünkü asıl ölçüm sayaçtı. Burada açıkça yazılmasının
nedeni şu: atomik sayaç, "paylaşılan veri artık güvenli biçimde değiştirilebilir" gibi bir
izlenim uyandırabilir, çünkü kelime "atomik" bir güvenceyi çağrıştırır. Ölçüm bu izlenimi
düzeltiyor — güvence yalnızca sayacın kendi tutarlılığı içindir, sayacın koruduğu değerin
içeriği için değil. İki kopya aynı anda aynı veriyi okuyabilir, ama hiçbiri onu tek başına
değiştiremez; değiştirme ihtiyacı ayrı bir araç gerektirir.

**PS9.** — "birden çok kopyanın aynı değeri okuyabildiği ama hiçbirinin onu değiştiremediği"
iddiası, aşağıdaki koşumun iki kopyadan da aynı `deger` alanını basmasıyla ve hiçbir yazma
satırı içermemesiyle doğrulanıyor.

```rust
// paylasilan_veri_salt_okunur.rs — Arc uzerinden yalniz okuma mumkun
use std::sync::Arc;

struct Olcum {
    deger: i64,
}

fn main() {
    let paylasilan = Arc::new(Olcum { deger: 42 });
    let kopya = Arc::clone(&paylasilan);

    println!("ilk okuma: {}", paylasilan.deger);
    println!("kopyadan okuma: {}", kopya.deger);
    println!("sayac: {}", Arc::strong_count(&paylasilan));
}
```

```
ilk okuma: 42
kopyadan okuma: 42
sayac: 2
```

İki kopya da aynı `deger` alanını okuyor ve ikisi de aynı sonucu veriyor, çünkü aslında
tek bir `Olcum` değeri var, iki kopya da ona erişiyor. Bu programda hiçbir satır `deger`
alanına yazmıyor — bu tesadüf değil, `Arc`in izin verdiği tek işlem okumadır. `deger`i
`43` yapmaya çalışan bir satır eklenseydi derlenmezdi; bu redd program içinde ayrıca
koşturulmuyor, çünkü derlenmeyen bir kaynak kod bloğuna konmuyor. Sayaç bu koşumda da
okunuyor (`sayac: 2`), ama bu satırın `deger` alanıyla hiçbir ilişkisi yok — biri kaç
kopya olduğunu, öbürü kopyaların baktığı değerin içeriğini söylüyor; ikisi birbirinden
bağımsız iki farklı soru.

Bu örnekte `Iz`/`defter` düzeneği yerine yalın bir `Olcum` yapısı kullanılıyor, çünkü
ölçülen şey bir bitiş kaydı değil, erişimin kendisi. Öbekte Tekil Sahiplik dersinde bir
`Box` üzerinden `nokta.x` okumanın, değerin doğrudan orada duruyormuş gibi çalıştığı
gösterilmişti; burada da `paylasilan.deger` ve `kopya.deger` aynı satır biçimini
kullanıyor. Fark şu: `Box`ta bu erişim hem okumaya hem yazmaya açıktı, çünkü tek sahip
vardı. `Arc`te aynı erişim yalnızca okumaya açık, çünkü sahiplik paylaşılıyor ve
paylaşılan bir değere kimin ne zaman yazdığını izleyen bir düzenek henüz devrede değil.

Üç ölçüm bir araya geldiğinde şu ortaya çıkıyor: `Arc`, sayaç düzeyinde `Rc`nin
güçlendirilmiş bir biçimidir, ama bu güçlendirme paylaşılan verinin kendisine hiç
sirayet etmez. Sayaç ne kadar sağlam güncellenirse güncellensin, verinin değiştirilebilir
olup olmadığı ayrı bir sorudur ve bu iki türün hiçbirinde henüz yanıtlanmıyor.

Bu konunun ilk üç dersi birlikte okunduğunda bir ilerleme görülüyor. Öbekte Tekil
Sahiplik, bir değerin öbekte durabildiğini ama sahibinin hâlâ tek olduğunu kurdu.
Referans Sayımı, bu tekliği bir sayaçla genişletilebilir hâle getirdi — sahiplik artık
sayılabilir bir kümeydi. Bu ders, o sayacın güncellenme biçimini değiştirilebilir bir
seçenek olarak sundu, ama sahiplik ve erişim modelinin kendisini değiştirmedi: kaç
kopya olursa olsun, hiçbiri değeri değiştiremiyor. Üç ders boyunca kap değişti, sayaç
değişti, ama içindeki değere yazma hakkı hiç doğmadı — bu hakkın nasıl kazanılacağı
kursun bir sonraki ve son sorusu. Üç dersin ortak paydası şu: her birinde bir değerin
ömrü hâlâ kaynaktan okunabiliyor, hiçbiri bu belirlenimciliği bozmuyor — yalnızca sahiplik
biçimi ve erişim hakkı derece derece genişliyor.

## Özet

- `Arc<T>`, `Rc<T>` ile aynı arayüzü taşır ve aynı "sayaç sıfıra inince değer biter"
  kuralını uygular.
- İki türün ürettiği bitiş kaydı ve sayaç dizisi birebir aynıdır — ikisinde de değerin
  ömrü **kabıyla birlikte** bitiyor; fark davranışta değil,
  sayacın atomik olarak güncellenmesindedir.
- Atomik güncellemenin hangi bağlamda gerektiği bu dersin konusu değildir, M10/K04'ündür.
- `Arc` üzerinden paylaşılan veri yalnızca okunabilir; bir alana doğrudan yazmak
  derlenmez.
- Atomik sayaç veriyi değil, yalnızca kendisini korur; paylaşılan verinin değiştirilemez
  kalması ayrı bir kısıttır.
- Her `Arc` değerinin kendi sayacı vardır ve bitiş, hangi kopyanın değil kaç kopyanın
  kaldığına bağlıdır — bu ilke `Rc` ile aynıdır.

## Sonraki Adım

Bu derste paylaşılan bir değerin okunabildiği ama değiştirilemediği ölçüldü. Bir sonraki
soru kaçınılmaz: paylaşılan bir değeri değiştirmek gerekirse ne olur? Değişkenler ve
Değişmezlik dersinde bir sınır açık bırakılmıştı: bağlamanın değişmezliği ile içindeki bir
alanın değişebilirliği ayrı sorulardı ve o ders yalnızca sınırı çizmişti, kapatmamıştı.
Sıradaki (ve bu konunun son) ders, ödünç denetiminin derleme zamanından çalışma zamanına
nasıl taşınabildiğini ve bu taşımanın hangi bedeli getirdiğini ölçerek o sınırı kapatıyor.
