Semafor Operasyonları
Semaforları, işaretsiz integer değerler olarak düşünebiliriz.
Bir semafor üzerinde, artırma ve azaltma yönünde iki temel operasyon gerçekleştirilebilir.
Operasyonel Semafor Fonksiyonları
sem_wait
Semaforun değerini 1 azaltmak için kullanılır.
Eğer ilgili semafor değeri 1'den büyükse azaltma işlemi anında gerçekleştirilir ve fonksiyon geri döner.
Semafor değeri zaten 0'a eşitse,
sem_wait
fonksiyonu, semaforun değerinin 1 artmasını bekler. Artış olduğunda hemen tekrar 0'a çeker ve fonksiyon geri döner.Yukarıdaki bloklanmış bekleme durumunda bir sinyal yakalanması halinde, sinyale ilişkin SA_RESTART bayrağının ayarlanmış olup olmamasından bağımsız olarak, EINTR hatasıyla fonksiyondan çıkılır.
Örnek: Semafor Bekleme
/* sem_wait.c */
#include <semaphore.h>
#include "common.h"
int main(int argc, char *argv[])
{
sem_t *sem;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s sem-name\n", argv[0]);
sem = sem_open(argv[1], 0);
if (sem == SEM_FAILED)
errExit("sem_open");
if (sem_wait(sem) == -1)
errExit("sem_wait");
printf("%ld sem_wait() succeeded\n", (long) getpid());
exit(EXIT_SUCCESS);
}
sem_trywait
ve sem_timedwait
Semafor bekleme operasyonu bir sinyal gelmediği müddetçe işlem gerçekleşene kadar çağıran süreci bloklamaktadır.
Bloklama yapması istenmediği durumda,
sem_trywait
kullanılabilir. Bu modelde eğer semafor değeri 1 ise azaltılıp başarılı döner, ancak değer zaten 0 ise bloklama yapılmaz ve EAGAIN hatası ile dönülür.Bekleme işlemi için maksimum zaman aralığını seçmek istersek,
sem_timedwait
fonksiyonunu kullanabiliriz. Bu durumda semafor değeri hemen azaltılamıyorsa, maksimum olarak verilen parametre süresi kadar bekleyecektir. Bu süre zarfında da işlemin gerçekleşmemesi halinde ETIMEDOUT hatası ile döner.
sem_post
Semaforun değerini 1 artırmak için kullanılır.
Eğer semaforun değeri zaten 0 ise ve başka bir süreç aynı semaforu beklediği için bloklanmış durumdaysa, ilgili süreç uyandırılır.
Yukarıdaki durumda birden fazla sürecin aynı semaforu beklerken bloklanması sözkonusu olursa, hangi sürecin uyandırılacağı garanti edilemez.
Örnek: Semafor Değerini Artırma
/* sem_post.c */
#include <semaphore.h>
#include "common.h"
int main(int argc, char *argv[])
{
sem_t *sem;
if (argc != 2)
usageErr("%s sem-name\n", argv[0]);
sem = sem_open(argv[1], 0);
if (sem == SEM_FAILED)
errExit("sem_open");
if (sem_post(sem) == -1)
errExit("sem_post");
exit(EXIT_SUCCESS);
}
sem_getvalue
- Mevcut bir semaforun o anki değerini almak için kullanılır.
Örnek
/* sem_get.c */
#include <semaphore.h>
#include "common.h"
int main(int argc, char *argv[])
{
int value;
sem_t *sem;
if (argc != 2)
usageErr("%s sem-name\n", argv[0]);
sem = sem_open(argv[1], 0);
if (sem == SEM_FAILED)
errExit("sem_open");
if (sem_getvalue(sem, &value) == -1)
errExit("sem_getvalue");
printf("%d\n", value);
exit(EXIT_SUCCESS);
}
İsimsiz Semaforlar
İsimsiz semaforlar, ortak bir bellek alanına erişimin mümkün olduğu tüm senaryolarda kullanılabilir.
İsimlendirilmiş semaforlardaki fonksiyonlar aynen kullanılabilir.
Bu fonksiyonlara ek olarak isimsize semaforlarda
sem_init
vesem_destroy
fonksiyonları da kullanılmaktadır.
sem_init
İlgili semaforun ilklendirilmesi işlemlerini gerçekleştirir.
Fonksiyonun 2. parametresi olan
pshared
değeri 0 olduğu takdirde, semafor sadece aynı sürecin thread'leri içerisinde kullanılabilir. Bu nedenle shared memory kullanımına gerek kalmadan, global bir değişkende veya heap üzerinde ayrılan bir alanda tutulabilir.pshared
değeri 0'dan farklı olursa, semafor farklı süreçler arasında kullanılabilir. Bu durumda 1. parametredeki adres, shared memory üzerindeki bir yeri göstermelidir.Bu fonksiyonun aynı semafor için birden fazla çağrılması durumunda sistem kararlı davranamaz. Bu nedenle, her semaforun sadece bir defa ilklendirilmesi garanti edilmelidir.
sem_destroy
İsimsiz bir semaforun sonlandırılmasını sağlar.
Semafor sonlandırılmadan, tutulduğu bellek bölgesi free edilmemelidir.
Örnek: İsimsiz semafor kullanımı
/* sem_unnamed.c */
#include <semaphore.h>
#include <pthread.h>
#include "common.h"
static int glob = 0;
static sem_t sem;
static void *threadFunc(void *arg)
{
int loops = *((int *) arg);
int loc, j;
for (j = 0; j < loops; j++) {
if (sem_wait(&sem) == -1)
errExit("sem_wait");
loc = glob;
loc++;
glob = loc;
if (sem_post(&sem) == -1)
errExit("sem_post");
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t t1, t2;
int loops, s;
loops = (argc > 1) ? getInt(argv[1], GN_GT_0, "num-loops") : 10000000;
/* Initialize a thread-shared mutex with the value 1 */
if (sem_init(&sem, 0, 1) == -1)
errExit("sem_init");
/* Create two threads that increment 'glob' */
s = pthread_create(&t1, NULL, threadFunc, &loops);
if (s != 0)
errExit("pthread_create");
s = pthread_create(&t2, NULL, threadFunc, &loops);
if (s != 0)
errExit("pthread_create");
/* Wait for threads to terminate */
s = pthread_join(t1, NULL);
if (s != 0)
errExit("pthread_join");
s = pthread_join(t2, NULL);
if (s != 0)
errExit("pthread_join");
printf("glob = %d\n", glob);
exit(EXIT_SUCCESS);
}