21 Mart 2017 Salı

Posix Eşzamanlılık Yapıları - Condition

Giriş
Şu satırı dahil ederiz.
#include <pthread.h>
POSIX Condition ve Win32 Event'leri arasındaki fark
Posix condition nesneleri state tutmaz. Yani bir condition tetiklendikten daha sonraki bir zamanda, beklemeye başlayan thread bloke olmaz. Event'ler ise bayrak gibidir. Birisi indirinceye kadar havada kalır. Autoreset event ise havada kalmaz ve otomatik indirilir. Condition'lar benzeyen nesneler (CONDITION_VARIABLE) Vista ile eklendiler.
Not : Producer/Consumer kuyruklarında Reader ve Writer için iki tane condition tanımlanır.

1. Condition Nasıl Tanımlanır
Şöyle yaparız.
pthread_cond_t cond;
2. pthread_cond_init metodu
Şöyle yaparız.
pthread_cond_init(&cond,NULL)
Eğer değişkenimiz global bir değişken ise şöyle yaparız.
pthread_cond_t cons = PTHREAD_COND_INITIALIZER;
3. pthread_cond_destroy metoduŞöyle yaparız.
pthread_cond_destroy(&cond);
4. pthread_cond_signal metoduAçıklaması şöyle
The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().
Tek bir thread'i uyandırır. Şöyle yaparız.
pthread_cond_signal(&cond); 
5. pthread_cond_broadcast metodu
Tüm thread'leri uyandırır.

6. pthread_cond_wait metodu
Şöyle yaparız.
pthread_cond_wait(&cond,&mutex);
Çağrının ilk parametresi pthread_cond değişkeni, ikinci parametre ise bir mutex değişkenidir. Bu çağrı koşul tetikleninceye kadar bekler. Tetiklenmeyi beklerken, ikinci parametre olarak verilen mutex unlock edilir, yani bayrak bırakılır. Böylece bir başka thread mutex'i alıp, işi gerçekleştirir ve koşulu tetikler.
Aşağıda bu metodun içini kavramsal olarak gösteren bir kod parçası var.
bool condition::wait_for(mutex& mutex) const {
    unlocker ul(mutex);    // relinquish mutex
    return wait(event);
}                          // ul's dtor grabs mutex again
6. pthread_cond_timedwait metoduŞöyle yaparız.
unsigned sleep_time = 1; 
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += sleep_time;
int timed_cond_rc = pthread_cond_timedwait(&cond, &mutex, &ts);
Doğru Kullanım Şekli
Doğru kullanım şekli ise şöyle.
while(1) {
  pthread_mutex_lock(&mutex);
  while(some_data == NULL) { // predicate to acccount for spurious wakeups
    pthread_cond_wait(&cond,&mutex); //atomically lock/unlock mutex
  }

  char *data = some_data;
  some_data = NULL;
  pthread_mutex_unlock(&mutex);
  handle(data);
}
while (some_data == NULL) koşuluna spurious wakeup problemi yüzünden gerek var. Bu koşul ile aynı condition nesnesi üzerinde bekleyen birden fazla threadin yanlış çalışması da engellenir.

Bir kuyrukta kullanım şekli ise şöyle. Her iki kullanım şeklinde de işlenecek veri alındıktan sonra önce pthread_mutex_unlock çağrısı yapılıyor. Daha sonra handle() veya do_work() ile thread yoluna devam ediyor.
while(1)
{
  pthread_mutex_lock(&work_mutex);

  while (work_queue_empty())       // wait for work
    pthread_cond_wait(&work_cv, &work_mutex);

  work = get_work_from_queue();    // get work

  pthread_mutex_unlock(&work_mutex);

  do_work(work);                   // do that work
}
Yanlış Kullanım Şekli
Şu kullanım şekli yanlış. pthread_cond_wait() çağrısının ilk parametresi pthread_cond değişkeni, ikinci parametre ise bir mutex olmalı.
void *threadRead() {
  while (1) {
    bzero(buffer,256);
    pthread_cond_wait(&buffer_lock, read(sockfd, buffer, 255) > 0);
    n = read(sockfd, buffer, 255);
    printf("%s\n",buffer);
  }
}







Hiç yorum yok:

Yorum Gönder