Concurrency
- C++ kursu
- Uzman
- Ders 45/47
- 6 dk
Concurrency ve memory model ile paralel yapı yazarsın.
std::thread ve std::atomic ile paralel toplam
Paralel iş için std::thread ile iki iş parçacığı başlatırız. Paylaşılan bir sayacı std::atomic<int> olarak tutarız; böylece iki iş parçacığı aynı anda güvenle yazabilir. total += i işlemi atomik olarak yapılır ve veri yarışı oluşmaz.
İş parçacıkları 1-4 ve 5-8 aralığını toplar. t1.join() ve t2.join() ile her iki iş parçacığının bitmesini bekleriz. Sonuç her zaman 36 olur; çünkü toplam sabittir, yalnızca yazma sırası değişir. Bu deterministik çıktı, atomic kullanımının güvenli olduğunu gösterir.
join ile bitmesini beklemek
Bir iş parçacığının bitmesini beklemek için join() çağrılır. t1.join() ana akışı durdurur ve t1 bitene kadar bekletir. Her iki iş parçacığı da bitince total tüm katkıları toplamış olur.
Sonuç 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36'dır. Yazma sırası farklı olsa da toplam değişmez. join'i unutursak program iş parçacıkları bitmeden sonlanabilir ve std::terminate çağrılır. Bu yüzden join zorunludur.
Uygulama parallelSum metodunu ekle ve çağır
Önceki dersin çözümünü al (Engine sınıfı ve Factorial şablonu var). Engine sınıfının public: bölümüne static int parallelSum() metodunu ekle. Gövdesinde std::atomic<int> total{0}; tanımla, iki std::thread başlat (1-4 ve 5-8 aralıkları), her ikisini de join ile bekle ve total.load() döndür. main içinde Factorial çıktısından sonra std::cout << std::endl << Engine::parallelSum(); ekle.
Başlangıç kodu
#include <iostream>
#include <atomic>
#include <thread>
class Engine {
public:
static const int Version = 1;
// parallelSum metodunu buraya ekle
};
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << "Hazır" << std::endl;
std::cout << Factorial<5>::value << std::endl;
// parallelSum sonucunu yazdır
return 0;
}Örnek çözüm
#include <iostream>
#include <atomic>
#include <thread>
class Engine {
public:
static const int Version = 1;
static int parallelSum() {
std::atomic<int> total{0};
std::thread t1([&]() { for (int i = 1; i <= 4; ++i) total += i; });
std::thread t2([&]() { for (int i = 5; i <= 8; ++i) total += i; });
t1.join();
t2.join();
return total.load();
}
};
template <int N>
struct Factorial {
static const int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << "Hazır" << std::endl;
std::cout << Factorial<5>::value << std::endl;
std::cout << Engine::parallelSum();
return 0;
}Beklenen çıktı
Hazır 120 36
Soru ve cevaplar
Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.
1 İki iş parçacığı paylaşılan bir sayacı güncellerken std::atomic ne sağlar?
std::atomic<int> total{0};- Veri yarışını önler Doğru cevap
- Bellek kullanımını azaltır
- İş parçacığı sayısını sınırlar
- Derleme süresini kısaltır
Açıklama: std::atomic her yazmayı atomik yapar; veri yarışı oluşmaz.
2 Atomic sayaç başlangıç değerini tamamla
std::atomic<int> total{____};
std::atomic<int> total{0};
Açıklama: Sayaç sıfırdan başlar ve katkılar eklenir.
3 Parçayı rolüne eşle
| Kavram | Anlamı |
|---|---|
std::thread |
İş parçacığı başlatır |
std::atomic<int> |
Paylaşılan güvenli sayaç |
t1.join() |
Bitmesini bekler |
total += i |
Atomik toplama |