Girdi ve Çıktının Beklenmesi
Önceki XIII. Oylum - Düşük Seviyeli Girdi ve Çıktı Sonraki
Girdi ve Çıktının Beklenmesi
Kimi zaman bir yazılımın girdiyi gelişine bağlı olarak çok sayıda girdi kanalından kabul etmesi gerekir. Örneğin bazı iş istasyonları tablet, işlev düğmeleri kutusu, normal eşzamansız seri arayüz üzerinden bağlanılan çevirmeli ağ gibi çok sayıda aygıttan aynı anda ve anında yanıt verecek iyi bir kullanıcı arayüzü gerektirmektedir. Başka bir örnek de bir yazılımın başka süreçlere borular ve FIFO'lar üzerinden bir sunucu olarak hizmet vermesidir.
Normalde bu amaçla read kullanamazsınız, çünkü işlev bir dosya tanıtıcıdan bir girdi gelene kadar beklerken diğer kanallardaki girdi fazladan bekletilir. Engellenmeyen kipe geçmeniz ve dosya tanıtıcılarını sürekli taramanız gerekir ki bu da pek verimli değildir.
Daha iyi bir çözüm select işlevini kullanmaktır. Bu, belirtilen dosya tanıtıcı kümesinde bir girdi ya da çıktı hazır olana kadar ya da bir zamanlayıcı zamanaşımına uğrayıncaya kadar (hangisi önce gerçekleşirse), bekler. Bu oluşum sys/types.h başlık dosyasında bildirilmiştir.
Bir sunucu soketi için konuşursak, askıda kabul edilmiş bağlantılar olduğunda girdinin var olabileceğinden söz edilebilir. accept işlevi sunucu soketini beklemeye alır ve read işlevinin normal girdi için yaptığı gibi select ile etkileşir.
select işlevi için dosya tanıtıcı kümeleri fd_set nesneleri olarak belirtilir. Burada bu nesnelerin veri türü ve bunlarla ilgili makrolara değinilecektir.
fd_set
veri türü
fd_set veri türü select işlevinin üzerlerinde işlem yaptığı dosya tanıtıcılarının kümesini içerir. Aslında bir bit dizisidir.
int FD_SETSIZE
makro
fd_set nesnesinde saklanabilen dosya tanıtıcılarının azami sayısıdır. Azami sayının sabit olduğu sistemlerde FD_SETSIZE bu sayıya eşittir. GNU sistemininde dahil olduğu bazı sistemlerde açık tanıtıcıların azami sayısı için mutlak bir üst sınır olmamasına rağmen fd_set içindeki bitlerin sayısını belirten sabit bir değerdir; FD_SETSIZE'ıncıdan sonra bir dosya tanıtıcıyı daha fd_set içine koyamazsınız.
void FD_ZERO
(fd_set *küme)
makro
Bu makro küme dosya tanıtıcı kümesini boş bir küme olarak ilklendirir.
void FD_SET
(int     dosyatanıtıcı,
 fd_set *küme)
makro
Bu makro dosyatanıtıcı dosya tanıtıcısını küme dosya tanıtıcı kümesine dahil eder.
dosyatanıtıcı parametresi birden fazla değerlendirildiğinden yan etkilere sahip olmamalıdır .
void FD_CLR
(int     dosyatanıtıcı,
 fd_set *küme)
makro
Bu makro dosyatanıtıcı dosya tanıtıcısını küme dosya tanıtıcı kümesinden kaldırır.
dosyatanıtıcı parametresi birden fazla değerlendirildiğinden yan etkilere sahip olmamalıdır .
int FD_ISSET
(int           dosyatanıtıcı,
 const fd_set *küme)
makro
Bu makro dosyatanıtıcı dosya tanıtıcısını küme dosya tanıtıcı kümesinin bir üyesi ise sıfırdan farklı bir değerle aksi takdirde sıfırla döner.
dosyatanıtıcı parametresi birden fazla değerlendirildiğinden yan etkilere sahip olmamalıdır .
int select
(int             dtsayısı,
 fd_set         *oku-dt,
 fd_set         *yaz-dt,
 fd_set         *diğer-dt,
 struct timeval *süre)
işlev
select işlevi, çağrıldığı süreci belirtilen dosya tananıtıcı kümesindeki tanıtıcılarda bir etkinlik olana kadar ya da belirtilen zamanaşımı süresi dolana kadar bekletir.
oku-dt argümanı ile okumaya hazır tanıtıcılar, yaz-dt argümanı ile yazmaya hazır tanıtıcılar belirtilir. diğer-dt ile belirtilen tanıtıcılar ise olağandışı durumlara göre denetlenir. İlgilenmediğiniz durumla ilgili olan argümana boş gösterici atayabilirsiniz.
Bir dosya gösterici eğer bir read çağrısı engellenmeyecekse okumaya hazır olarak kabul edilir. Engellenme durumları olarak okuma başlangıcının dosyanın sonunda olması veya raporlanacak bir hatanın varlığından bahsedilebilir. Bir sunucu soketi de accept ile kabul edilebilen bir bağlantı askıdaysa okumaya hazır kabul edilir. Bir istemci soketi ise bağlantı tamamen kurulduğunda yazmaya hazır olur.
"Olağandışı durumlar" hata anlamında değildir; hatalar oluştuğunda sistem çağrıları tarafından raporlanır ve bunların tanıtıcının durumu ile ilgisi yoktur. Olağandışı durumlar bir soket üzerinde acil bir iletinin varlığı gibi durumlardır. (Acil iletiler hakkında Soketler bölümünde bilgi bulabilirsiniz.)
select işlevi sadece ilk dtsayısı dosya tanıtıcısını denetler. dtsayısı olarak FD_SETSIZE çok kullanışlıdır.
süre azami bekleme süresini belirtir. Bir boş gösterici belirtmişseniz bir süre sınırı olmaksızın bir dosya tanıtıcı hazır olana kadar işlev bekleyecektir. Bunun olmaması için struct timeval biçiminde bir zamanaşımı süresi belirtmelisiniz. Beklemeden hangi dosya tanıtıcıların hazır olduğuna bakmak isterseniz buraya süre olarak sıfır (struct timeval'ın üyelerinin hepsi sıfır) belirtebilirsiniz.
İşlevin normal dönüş değeri tüm kümelerde hazır olan dosya tanıtıcıların sayısıdır. Küme argümanlarının her birinde hazır olan tanıtıcılarla ilgili bilgi bulunur. select döndükten sonra belli bir dosya tanıtıcının girdi için hazır olup olmadığını
FD_ISSET (dosyatanıtıcı, oku-dt) ile öğrenebilirsiniz.
select zamanaşımına uğramışsa sıfır ile döner.
Herhangi bir sinyal select işlevinin anında dönmesine sebep olur. Yazılımınızda sinyaller kullanılıyorsa belirttiğiniz zamanaşımı süresince işlevin beklemede kalması mümkün olmayabilir. Bu sürenin mutlaka beklenmesini istiyorsanız EINTR durumunun varlığına bakarak o anki zaman değeri ile karşılaştırarak yeni bekleme süresini hesaplayıp çağrıyı yinelemelisiniz. Bunun bir örneği aşağıda verilmiştir, ayrıca Sinyallerle Kesilen İlkeller bölümüne de bakın.
Bir hata oluşursa işlev -1 ile döner ve dosya tanıtıcı kümesi argümanlarında bir değişiklik yapmaz. Aşağıdaki errno hata durumları bu işlev için tanımlanmıştır:
EBADF
Dosya tanıtıcı kümelerinden biri geçersiz bir dosya tanıtıcı içeriyor
EINTR
İşlem bir sinyalle durduruldu. Bkz. Sinyallerle Kesilen İlkeller.
EINVAL
süre argümanı geçersiz; üyelerinden biri ya negatif ya da çok büyük
Taşınabilirlik Bilgisi
select işlevi bir BSD Unix özelliğidir.
Bu örnekte bir dosya tanıtıcısının okumaya hazır olmasını belli bir süre beklemek için select işlevinin kullanımı gösterilmiştir. input_timeout işlevi çağrıldığı süreci dosya tanıtıcı üzerinde bir girdi olana kadar ya da belli bir zamanaşımına kadar bekletir.
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>

int
input_timeout (int filedes, unsigned int seconds)
{
  fd_set set;
  struct timeval timeout;

  /* Dosya tanıtıcı kümesini ilklendirelim. */
  FD_ZERO (&set);
  FD_SET (filedes, &set);

  /* Zamanaşımı yapısını ilklendirelim. */
  timeout.tv_sec = seconds;
  timeout.tv_usec = 0;

  /* select, zamanaşımına uğrarsa 0 ile,
     girdi varsa 1 ile, hata oluşursa -1 ile döner. */
  return TEMP_FAILURE_RETRY (select (FD_SETSIZE,
                                      &set, NULL, NULL,
                                      &timeout));
}

int
main (void)
{
  fprintf (stderr, "select %d ile döndü.\n",
            input_timeout (STDIN_FILENO, 5));
  return 0;
}
select işlevinin çok sayıda soketten çoklu girdi alınması ile ilgili kullanım örneğini Bayt Akımlı Bağlantı Sunucusu Örneği bölümünde bulabilirsiniz.
Önceki Üst Ana Başlık Sonraki
Bellek Eşlemli G/Ç Başlangıç G/Ç İşlemlerinin Eşzamanlanması
Bir Linux Kitaplığı Sayfası