---
title: 'Dosya Tanıtıcıları'
source: 'https://academia.sh/tr/kurslar/c-sistem-programlama/dosya-taniticilari'
course: 'C ile Sistem Programlama'
language: tr
updated: '2026-09-26T03:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'dört sınıfı (kopya, ortak, aktarım, gözlenmeyen) çekirdeğin tek bir koşumundaki on beş gözlemle ayırt eder'
    - 'dup ile çoğaltılan bir tanıtıcının aynı açık dosya kaydını paylaştığını konum davranışıyla gösterir'
    - 'ayrı bir open çağrısının neden ayrı bir konum tuttuğunu, iki tanıtıcının sayısal değerine bakmadan açıklar'
---

# Dosya Tanıtıcıları

Bir işaretçinin aynı bellek konumunu gösterip göstermediği eşitlikle ölçülür; bir dosya tanıtıcısının aynı açık dosya kaydını paylaşıp paylaşmadığı ise konum davranışıyla ölçülür — tanıtıcının kendisi bir tamsayıdır ve hiçbir şey söylemez.

Önceki kurs bir bloğu kimin bırakacağını sordu: bir işaretçi bir kaydı gösterdiğinde,
o kaydı serbest bırakma yükümlülüğü hangi tarafa aitti. Bu kurs farklı bir soru sorar.
Bir taraf bir şeyi değiştirdiğinde öteki taraf bunu görür mü? `fork` belleği çoğaltır,
`dup` bir açık dosyayı paylaştırır, bir iş parçacığı adres uzayını paylaşır, bir boru
baytları bir kez taşır. Her düzenek bu soruya farklı yanıt verir, ve kurs boyunca bu
yanıtın dört sabit adı var: **kopya**, **ortak**, **aktarım**, **gözlenmeyen**. Bu ders
dördünü tek bir koşumda gösteriyor, sonra ilkine — dosya tanıtıcılarına — biraz daha
yakından bakıyor.

## Kim Görüyor Sorusu: Çekirdeğin Tam Koşumu

Ölçüm iki parçadan kuruluyor. `gozlem.h` ve `gozlem.c`, bir değişikliğin adını, sınıfını
ve öteki tarafın onu görüp görmediğini kaydeden küçük bir birim. Sayılar yalnız
`gozlem.c` içinde tutuluyor; hiçbir ders bu sayılara dışarıdan dokunmuyor.

```c
// gozlem.h — bir degisikligin kime ulastigini siniflayan kayit
#ifndef GOZLEM_H
#define GOZLEM_H

enum Sinif { KOPYA, ORTAK, AKTARIM, GOZLENMEYEN };

/* Bir degisikligi kaydeder: gordu, degisikligi yapmayan tarafin onu
   okuyup okuyamadigidir (1 ya da 0). */
void gozlem(const char *degisiklik, enum Sinif sinif, int gordu);

/* Sinif basina sayilari ve ulasan / ulasmayan toplamini basar. */
void gozlem_ozeti(void);

#endif
```

```c
// gozlem.c — sayilar yalniz bu birimde tutulur
#include <stdio.h>
#include "gozlem.h"

static const char *const adlar[] = { "kopya", "ortak", "aktarim", "gozlenmeyen" };
static int sayilar[4];
static int ulasan = 0;
static int ulasmayan = 0;

void gozlem(const char *degisiklik, enum Sinif sinif, int gordu) {
    /* ortak ve aktarim ulasir, kopya ve gozlenmeyen ulasmaz */
    int beklenen = (sinif == ORTAK || sinif == AKTARIM);
    sayilar[sinif]++;
    if (gordu) {
        ulasan++;
    } else {
        ulasmayan++;
    }
    printf("%-34s %-8s %s%s\n", degisiklik, gordu ? "gordu" : "gormedi",
           adlar[sinif], gordu == beklenen ? "" : "  TUTARSIZ");
}

void gozlem_ozeti(void) {
    printf("siniflar: kopya %d, ortak %d, aktarim %d, gozlenmeyen %d\n",
           sayilar[KOPYA], sayilar[ORTAK], sayilar[AKTARIM], sayilar[GOZLENMEYEN]);
    printf("ulasan %d, ulasmayan %d\n", ulasan, ulasmayan);
}
```

Üçüncü birim, `gorur.c`, on beş küçük değişikliğin her birini bu iki işlevle ölçüyor.
Bu ders çekirdeğin **tamamını** koşturuyor; kalan on dört ders yalnız kendi kesitini
alacak, bu dosyayı yeniden yazmayacak.

```c
// gorur.c — on bes degisiklik, her biri icin tek soru: kim goruyor
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include "gozlem.h"

/* 1. Dosya tanitici: dup ile cogaltilan tanitici konumu paylasir */
static void tanitici(void) {
    int a = open("gorur.txt", O_CREAT | O_RDWR | O_TRUNC, 0600);
    if (write(a, "abcdef", 6) != 6) {
        return;
    }
    int b = dup(a);
    lseek(a, 2, SEEK_SET);
    gozlem("dup ile cogaltilan konum", ORTAK, lseek(b, 0, SEEK_CUR) == 2);
    close(b);
    close(a);
    unlink("gorur.txt");
}

/* 2. Surec: cocugun yazdigi degisken ebeveynde degismez */
static void surec(void) {
    int deger = 0;
    fflush(stdout);
    pid_t p = fork();
    if (p == 0) {
        deger = 1;
        _exit(deger);
    }
    int durum = 0;
    waitpid(p, &durum, 0);
    gozlem("fork sonrasi cocugun degiskeni", KOPYA, deger == 1);
}

/* 3. Sinyal: isleyicinin kaldirdigi bayrak ana akisa bir kez ulasir */
static volatile sig_atomic_t bayrak = 0;
static void isleyici(int s) {
    (void)s;
    bayrak = 1;
}
static void sinyal(void) {
    struct sigaction sa;
    memset(&sa, 0, sizeof sa);
    sa.sa_handler = isleyici;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGUSR1, &sa, NULL);
    raise(SIGUSR1);
    gozlem("isleyicinin kaldirdigi bayrak", AKTARIM, bayrak == 1);
}

/* 4. Boru: cocugun yazdigi deger ebeveyne bir kez tasinir */
static void boru(void) {
    int uc[2];
    if (pipe(uc) != 0) {
        return;
    }
    fflush(stdout);
    pid_t p = fork();
    if (p == 0) {
        int deger = 42;
        close(uc[0]);
        ssize_t n = write(uc[1], &deger, sizeof deger);
        _exit(n == (ssize_t)sizeof deger ? 0 : 1);
    }
    close(uc[1]);
    int okunan = 0;
    ssize_t n = read(uc[0], &okunan, sizeof okunan);
    waitpid(p, NULL, 0);
    close(uc[0]);
    gozlem("boruya yazilan deger", AKTARIM, n == (ssize_t)sizeof okunan && okunan == 42);
}

/* 5. Is parcacigi: kilitle artirilan sayac ana is parcacigina ulasir */
static int sayac = 0;
static pthread_mutex_t kilit = PTHREAD_MUTEX_INITIALIZER;
static void *artir(void *arg) {
    (void)arg;
    pthread_mutex_lock(&kilit);
    sayac = 7;
    pthread_mutex_unlock(&kilit);
    return NULL;
}
static void is_parcacigi(void) {
    pthread_t t;
    pthread_create(&t, NULL, artir, NULL);
    pthread_join(t, NULL);
    pthread_mutex_lock(&kilit);
    int gordu = (sayac == 7);
    pthread_mutex_unlock(&kilit);
    gozlem("is parcaciginin yazdigi sayac", ORTAK, gordu);
}

/* 6. Bagli yapi: ikinci isaretciden yapilan degisiklik listede gorunur */
struct Dugum {
    int deger;
    struct Dugum *sonraki;
};
static void bagli(void) {
    struct Dugum c = { 3, NULL };
    struct Dugum b = { 2, &c };
    struct Dugum a = { 1, &b };
    struct Dugum *takma = &b;
    takma->deger = 20;
    int toplam = 0;
    for (struct Dugum *d = &a; d != NULL; d = d->sonraki) {
        toplam += d->deger;
    }
    gozlem("takma adla degisen dugum", ORTAK, toplam == 24);
}

/* 7. Halka arabellek: konan oge alan tarafa bir kez ulasir */
enum { KAPASITE = 4 };
struct Halka {
    int ogeler[KAPASITE];
    int bas;
    int adet;
};
static int halka_koy(struct Halka *h, int oge) {
    if (h->adet == KAPASITE) {
        return 0;
    }
    h->ogeler[(h->bas + h->adet) % KAPASITE] = oge;
    h->adet++;
    return 1;
}
static int halka_al(struct Halka *h, int *oge) {
    if (h->adet == 0) {
        return 0;
    }
    *oge = h->ogeler[h->bas];
    h->bas = (h->bas + 1) % KAPASITE;
    h->adet--;
    return 1;
}
static void halka(void) {
    struct Halka h = { { 0 }, 0, 0 };
    int alinan = 0;
    halka_koy(&h, 5);
    int ilk = halka_al(&h, &alinan) && alinan == 5;
    int ikinci = halka_al(&h, &alinan);
    gozlem("halkaya konan oge", AKTARIM, ilk && !ikinci);
}

/* 8. Karma tablosu: tablo anahtarin kendi kopyasini tutar */
struct Girdi {
    char anahtar[16];
    int deger;
};
static void karma(void) {
    char tampon[16] = "elma";
    struct Girdi g;
    strcpy(g.anahtar, tampon);
    g.deger = 1;
    strcpy(tampon, "armut");
    gozlem("eklendikten sonra degisen anahtar", KOPYA, strcmp(g.anahtar, "armut") == 0);
}

/* 9. Nesne benzeri tasarim: ayni nesneyi tutan iki kullanici */
struct Hesap {
    int bakiye;
};
static void hesap_yatir(struct Hesap *h, int tutar) {
    h->bakiye += tutar;
}
static int hesap_bakiye(const struct Hesap *h) {
    return h->bakiye;
}
static void nesne(void) {
    struct Hesap hesap = { 0 };
    struct Hesap *birinci = &hesap;
    const struct Hesap *ikinci = &hesap;
    hesap_yatir(birinci, 50);
    gozlem("bir kullanicinin yaptigi yatirma", ORTAK, hesap_bakiye(ikinci) == 50);
}

/* 10. Temizleme: bosaltilmayan tampon _exit ile yok olur */
static void temizleme(void) {
    int uc[2];
    if (pipe(uc) != 0) {
        return;
    }
    fflush(stdout);
    pid_t p = fork();
    if (p == 0) {
        close(uc[0]);
        FILE *akis = fdopen(uc[1], "w");
        if (akis == NULL) {
            _exit(1);
        }
        setvbuf(akis, NULL, _IOFBF, 256);
        fputs("tamponda kalan satir\n", akis);
        _exit(0);
    }
    close(uc[1]);
    char gelen[64];
    ssize_t n = read(uc[0], gelen, sizeof gelen);
    waitpid(p, NULL, 0);
    close(uc[0]);
    gozlem("bosaltilmadan cikilan tampon", GOZLENMEYEN, n > 0);
}

/* 11. Derleme sistemi (model): bagimliligi yazilmamis birim yeniden derlenmez */
struct Birim {
    int baslik_bagimli_mi;
    int derlendigi_surum;
};
static void derle(struct Birim *b, int baslik_surumu, int baslik_zamani, int nesne_zamani) {
    if (b->baslik_bagimli_mi && baslik_zamani > nesne_zamani) {
        b->derlendigi_surum = baslik_surumu;
    }
}
static void derleme(void) {
    struct Birim birim = { 0, 1 };
    derle(&birim, 2, 20, 10);
    gozlem("bagimliligi yazilmamis baslik", KOPYA, birim.derlendigi_surum == 2);
}

/* 12. Kitaplik (model): statik baglama kodun bir kopyasini alir */
struct Kitaplik {
    int surum;
};
struct Program {
    int gomulu_surum;
    const struct Kitaplik *bagli;
};
static void kitaplik(void) {
    struct Kitaplik k = { 1 };
    struct Program statik = { k.surum, NULL };
    k.surum = 2;
    gozlem("statik bagli kitaplik guncellemesi", KOPYA, statik.gomulu_surum == 2);
}

/* 13. Test: ayri surecte kosan testin degisikligi sonrakine gecmez */
static int ortak_durum = 0;
static void test(void) {
    fflush(stdout);
    pid_t p = fork();
    if (p == 0) {
        ortak_durum = 9;
        _exit(0);
    }
    waitpid(p, NULL, 0);
    gozlem("yalitilmis testin degisikligi", KOPYA, ortak_durum == 9);
}

/* 14. Hata ayiklayici (model): iki durak arasindaki ara deger */
static void hata_ayiklayici(void) {
    int degerler[3] = { 1, 2, 3 };
    int gorulen[2];
    gorulen[0] = degerler[0]; /* birinci durak */
    gorulen[1] = degerler[2]; /* ikinci durak */
    gozlem("iki durak arasindaki ara deger", GOZLENMEYEN,
           gorulen[0] == 2 || gorulen[1] == 2);
}

/* 15. Eniyileme (model): hicbir okumanin gormedigi yazma */
struct Adim {
    char islem;
    int deger;
};
static void eniyileme(void) {
    struct Adim akis[] = { { 'y', 1 }, { 'y', 2 }, { 'o', 0 } };
    int okuyan = 0;
    int son_yazma = -1;
    for (int i = 0; i < 3; i++) {
        if (akis[i].islem == 'y') {
            son_yazma = i;
        } else if (son_yazma == 0) {
            okuyan++;
        }
    }
    gozlem("okunmadan ezilen yazma", GOZLENMEYEN, okuyan > 0);
}

int main(void) {
    tanitici();
    surec();
    sinyal();
    boru();
    is_parcacigi();
    bagli();
    halka();
    karma();
    nesne();
    temizleme();
    derleme();
    kitaplik();
    test();
    hata_ayiklayici();
    eniyileme();
    gozlem_ozeti();
    return 0;
}
```

```text
dup ile cogaltilan konum           gordu    ortak
fork sonrasi cocugun degiskeni     gormedi  kopya
isleyicinin kaldirdigi bayrak      gordu    aktarim
boruya yazilan deger               gordu    aktarim
is parcaciginin yazdigi sayac      gordu    ortak
takma adla degisen dugum           gordu    ortak
halkaya konan oge                  gordu    aktarim
eklendikten sonra degisen anahtar  gormedi  kopya
bir kullanicinin yaptigi yatirma   gordu    ortak
bosaltilmadan cikilan tampon       gormedi  gozlenmeyen
bagimliligi yazilmamis baslik      gormedi  kopya
statik bagli kitaplik guncellemesi gormedi  kopya
yalitilmis testin degisikligi      gormedi  kopya
iki durak arasindaki ara deger     gormedi  gozlenmeyen
okunmadan ezilen yazma             gormedi  gozlenmeyen
siniflar: kopya 5, ortak 4, aktarim 3, gozlenmeyen 3
ulasan 7, ulasmayan 8
```

**SA1.** On beş satırın hiçbiri `TUTARSIZ` işareti taşımıyor: her gözlem beklenen sınıfla
uyuşuyor. Beş değişiklik kopya, dört ortak, üç aktarım, üç gözlenmeyen — ve yedisi
öteki tarafa ulaşırken sekizi ulaşmıyor. Bu on beş satırlık liste kursun geri kalanının
haritası: her ders burada geçen bir satırı alıp derinleştiriyor. Bu dersin payı ilk
satır: `dup ile cogaltilan konum`.

## dup ile Çoğaltılan Konum

**SA2.** `tanitici` işlevi bir dosyayı `a` tanıtıcısıyla açıyor, altı bayt yazıyor, sonra `dup(a)`
ile ikinci bir tanıtıcı — `b` — türetiyor. `a` üzerinden konum ikiye alınıyor;
ölçülen soru, `b` üzerinden okunan konumun da ikiye gelip gelmediği. Çıktı `gordu`
diyor, yani geldi. Bunun nedeni tanıtıcı sayılarında değil, işletim sisteminin tuttuğu
üç katmanlı yapıda: her süreç kendi tanıtıcı tablosunu tutar, her tanıtıcı bir **açık
dosya kaydına** işaret eder, her açık dosya kaydı da bir **konum** taşır. `open` her
çağrıldığında yeni bir açık dosya kaydı — ve onunla yeni bir konum — oluşturur. `dup`
ise yeni bir kayıt açmaz; var olan kaydı gösteren ikinci bir tanıtıcı verir. `a` ve `b`
farklı tamsayılar, ama aynı kaydı gösteriyorlar; konumu biri değiştirdiğinde öteki de
aynı konumu okuyor.

Aynı dosyayı `open` ile iki kez açmış olsaydık — `a`'yı bir kez, sonra aynı yolu ikinci
bir çağrıyla `c` olarak — durum farklı olurdu. İki ayrı açık dosya kaydı oluşurdu, ikisi
de kendi konumunu tutardı; `a` üzerinden konum ikiye alındığında `c` sıfırda kalırdı.
Kayıt paylaşımı `open` ile değil, aynı kaydı **gösteren** bir tanıtıcı türetmekle
kurulur: `dup`, `dup2`, ya da `fork` sırasında miras alınan tanıtıcılar. `gorur.c`
bu ayrımı `dup` ile gösteriyor; sonraki ders aynı mirası `fork`la sürdürecek, ama
orada paylaşılan konum değil, çoğaltılan bellek konusu.

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

Bir tanıtıcı yalnız küçük bir tamsayıdır; kendi başına hiçbir şey söylemez. İki tanıtıcı
aynı kayda mı, yoksa iki ayrı kayda mı bakıyor — bu, sayısal değerlerine bakarak asla
anlaşılmaz. Tek güvenilir ölçüm, kaydın taşıdığı **konumun** davranışıdır: biri
üzerinden değiştirilen konum ötekinden de okunuyorsa kayıt paylaşılıyordur; okunmuyorsa
iki ayrı kayıt vardır. `gorur.c` bu yüzden konum değerini `lseek(b, 0, SEEK_CUR)` ile
okuyor, tanıtıcı sayısını hiçbir yerde basmıyor — tanıtıcı numarası hedefe ve koşuma
bağlıdır, konum davranışı bağlı değildir.

## Özet

- Kurs boyunca sabit kalan dört sınıf — kopya, ortak, aktarım, gözlenmeyen — tek bir
  soruya yanıt verir: değişikliği yapmayan taraf onu görüyor mu.
- Çekirdeğin on beş gözlemi beş kopya, dört ortak, üç aktarım, üç gözlenmeyen olarak
  dağılıyor; yedisi öteki tarafa ulaşıyor, sekizi ulaşmıyor.
- `dup` ile türetilen bir tanıtıcı yeni bir açık dosya kaydı açmaz; var olan kaydı
  gösteren ikinci bir yol açar, bu yüzden konumu paylaşır.
- Ayrı bir `open` çağrısı her zaman ayrı bir açık dosya kaydı, dolayısıyla ayrı bir
  konum yaratır — aynı dosyaya baksa bile.
- Bu dersin sınıfı **ortak**: iki tanıtıcı aynı kaydı tuttuğu için biri değiştirdiğinde
  öteki de görüyor.

## Sonraki Adım

Bir sonraki ders aynı soruyu `fork`a soruyor. `dup` bir kaydı paylaştırdı; `fork` ise
belleği paylaştırmaz, çoğaltır — çocuğun değişkeni kendi kopyasında kalır, ebeveyn
hiçbir zaman görmez.
