C'de Mutex ve Semaphore ile Thread Senkronizasyonu
Birden fazla thread aynı kaynağa eriştiğinde veri bozulması kaçınılmazdır. Mutex ve Semaphore bu sorunu çözen iki temel mekanizmadır.
Mutex (mutual exclusion) kritik bölüme bir seferde yalnızca bir thread'in girmesini sağlar. Semaphore ise sayaç tabanlıdır, belirli sayıda thread'in kaynağa erişmesine izin verir. Binary semaphore mutex gibi davranırken, counting semaphore havuz yönetiminde kullanışlıdır.
Pratik bir örnek: iki thread'in aynı sayacı artırması. Senkronizasyon olmadan sonuç yanlış çıkar.
1#include <stdio.h>2#include <pthread.h>3#include <semaphore.h>4#include <unistd.h>56int counter = 0;7sem_t sem;89void* increment_counter(void* arg) {10for (int i = 0; i < 1000000; i++) {11sem_wait(&sem); // Kritik bölüme gir12counter++;13sem_post(&sem); // Kritik bölümden çık14}15return NULL;16}1718int main() {19pthread_t t1, t2;2021sem_init(&sem, 0, 1); // Binary semaphore (1 = açık)2223pthread_create(&t1, NULL, increment_counter, NULL);24pthread_create(&t2, NULL, increment_counter, NULL);2526pthread_join(t1, NULL);27pthread_join(t2, NULL);2829printf("Counter: %d (beklenen: 2000000)\n", counter);30sem_destroy(&sem);3132return 0;33}Derle ve çalıştır:
1gcc -pthread -o sync sync.c./syncBeklenen çıktı: `Counter: 2000000`
Semaphore olmadan çalıştırırsan sonuç her defasında farklı çıkar, race condition nedeniyle. `sem_wait()` sayacı 1 azaltıp beklerse, `sem_post()` onu 1 artırır. Sayaç 0 olunca diğer thread'ler bekler.
Mutex ile aynı işlem:
1pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;23void* increment_with_mutex(void* arg) {4for (int i = 0; i < 1000000; i++) {5pthread_mutex_lock(&lock);6counter++;7pthread_mutex_unlock(&lock);8}9return NULL;10}Mutex daha basit ve okunması kolay. Semaphore ise birden fazla kaynağı yönetmek için tercih edilir, örneğin havuzda 3 bağlantı varsa `sem_init(&sem, 0, 3)` ile başla.
Sık hata: `sem_wait()` çağrısından sonra exception fırlatılırsa `sem_post()` asla çalışmaz ve deadlock oluşur. Bu yüzden C++'da `lock_guard` veya Rust'ta ownership mekanizması tercih edilir. C'de güvenli olmak için try-catch yerine `goto cleanup` deseni kullan.
0 yorum