9.1 Teorik Temel: Eşzamanlılık ve Paralellik Ayrımı
Akademik literatürde Eşzamanlılık (Concurrency), birden fazla görevin aynı zaman dilimi içerisinde "ilerleme" kaydetmesidir (mantıksal paralellik). Paralellik (Parallelism) ise, fiziksel olarak birden fazla görevin farklı işlemci çekirdeklerinde aynı anda (at the same time) çalışmasıdır.
Hafıza Modeli (Memory Model)
C++11 ile tanımlanan bellek modeli, farklı iş parçacıklarının (threads) ortak belleğe nasıl erişeceğini ve atomik işlemlerin (atomic operations) donanım seviyesindeki garantilerini belirler.
Veri Yarışı (Race Condition)
En az iki iş parçacığının aynı bellek bölgesine erişmesi ve bunlardan en az birinin "yazma" (write) işlemi yapması durumudur. Bu durum Tanımsız Davranış (Undefined Behavior) ile sonuçlanır.
9.2 İş Parçacığı (Thread) Akış Diyagramı
Şema 9.1: C++20 std::jthread ile Güvenli İş Parçacığı Yönetimi
9.3 Uygulama: Modern Senkronizasyon ve jthread
#include <iostream>
#include <thread> // std::jthread (C++20)
#include <mutex> // Karşılıklı Dışlama (Mutual Exclusion)
#include <vector>
#include <syncstream> // C++20: thread-safe çıktı akışı
std::mutex g_mutex; // Paylaşılan kaynağı korur
int g_sayac = 0;
/**
* @brief Akademik Örnek: Karşılıklı Dışlama (Mutual Exclusion) ve jthread
* MISRA C++:2023 Rule: Paylaşılan kaynaklara erişim daima kilitlenmelidir (locked).
*/
void guvenli_artir(std::stop_token st, int id) {
while (!st.stop_requested()) { // C++20: Durdurma sinyali kontrolü
std::lock_guard<std::mutex> kilit(g_mutex); // RAII: Kilit otomatik bırakılır
if (g_sayac < 100) {
g_sayac++;
std::osyncstream(std::cout) << "ID: " << id << " | Sayac: " << g_sayac << std::endl;
} else {
break;
}
}
}
int main() {
std::vector<std::jthread> havuz;
for (int i = 0; i < 4; ++i) {
// std::jthread: Yaşam süresi bittiğinde otomatik join() yapar.
havuz.emplace_back(guvenli_artir, i);
}
// jthread'ler burada kapsam dışına çıkar ve ana thread (main) bekler.
return 0;
}
Mimarın Analizi:
std::jthread (C++20), geleneksel `std::thread`'in en büyük zayıflığı olan manuel `join()` veya `detach()` zorunluluğunu ortadan kaldırır. Eğer bir `std::thread` yok edilmeden önce join edilmezse, program `std::terminate` ile çöker. `jthread` bu süreci RAII prensibiyle otomatikleştirir. Ayrıca stop_token mekanizmasıyla iş parçacıklarını dışarıdan güvenli bir şekilde durdurmamıza olanak tanır.
Karşılıklı Dışlama (Mutual Exclusion):
`std::mutex`, Kritik Bölge (Critical Section) olarak adlandırılan kod parçasına aynı anda sadece bir iş parçacığının girmesini garanti eder. `std::lock_guard` kullanımı, bir istisna fırlatılsa bile kilidin (lock) serbest bırakılmasını sağlayarak Ölümcül Kilitlenme (Deadlock) riskini azaltır.
⚠️ Concurrency Antipatterns (Hatalı Yaklaşımlar)
Ölümcül Kilitlenme (Deadlock)
İki iş parçacığının, birbirlerinin elindeki kilitleri (locks) beklemesi durumudur.
Çözüm: Kilitleme sırasına (lock order) dikkat edin veya C++17 `std::scoped_lock` kullanarak birden fazla mutex'i aynı anda kilitleyin.
Sahte Uyanma (Spurious Wakeups)
Koşul Değişkenleri (Condition Variables) kullanılırken, iş parçacığının sinyal gelmeden uyanmasıdır.
Akademik Not: `wait()` fonksiyonu daima bir `while` döngüsü veya lambda yüklemi (predicate) ile kullanılmalıdır.
9.5 Concurrency Bilgi Ölçümü
Soru: C++20 'std::jthread' sınıfını geleneksel 'std::thread'den ayıran en önemli mimari özellik nedir?
Pratik Görev (Telegram Challenge):
"trcpp-telegram topluluğunda 'Atomic Operations vs Mutex' tartışması yaygındır. Bir tamsayıyı 1.000.000 kez artırmak için 'std::atomic<int>' kullanarak kilit (mutex) kullanmadan veri yarışını (race condition) engelleyen bir kod parçası tasarlayın."