C++ programlama dilinde eşzamanlılık ve paralelleştirme işlemleri oldukça önemlidir ve thread kavramı sayesinde birden fazla iş parçacığı oluşturmak mümkündür C++11'den beri geliştirilen Parallel STL kütüphanesi ile işlemler paralel olarak yürütülebilir ve performans arttırılabilir Bununla birlikte, bu işlemlerde data races gibi sorunlarla karşılaşılabilir ve senkronizasyon araçları kullanmak önemlidir C++20 ile coroutine kavramı ve atomic smart pointer gibi yeni özellikler de eklenmiştir ve eşzamanlılık ve paralelleştirme işlemleri daha da geliştirilmiştir

Eşzamanlılık ve paralelleştirme, programlama dillerinde oldukça önemli kavramlardır. Eşzamanlılık, birden fazla işlemin ya da programın aynı anda çalışabilmesi durumudur. Paralelleştirme ise birden fazla işlemin aynı anda çalıştırılması anlamına gelir.
C++ programlama dilinin sunduğu özellikler sayesinde eşzamanlılık ve paralelleştirme işlemleri oldukça kolay bir şekilde gerçekleştirilebilir. C++'ta thread kavramı sayesinde, programda birden fazla iş parçacığı oluşturmak mümkündür.
Ayrıca, C++11'den beri Parallel STL adı verilen paralel standart kitaplığı geliştirilmiştir. Bu kitaplık sayesinde, STL algoritmaları paralelleştirilerek işlem zamanı önemli ölçüde azaltılabilir. Örneğin, partial sum ve sort algoritmaları kullanarak paralelleştirme işlemi gerçekleştirmek mümkündür.
Tabii ki, eşzamanlılık ve paralelleştirme işlemleri gerçekleştirilirken data races gibi sorunlarla karşılaşılabilir. Bu sorunları önlemenin yolları da C++ ile beraber sunulan özellikler arasında yer almaktadır.
C++20 ile birlikte, coroutine kavramı ve atomic smart pointer gibi yeni özellikler de eklenmiştir. Böylece, C++ ile eşzamanlılık ve paralelleştirme işlemleri daha da geliştirilmiş ve kolaylaştırılmıştır.
C++ ile Eşzamanlılık ve Paralelleştirme
C++ programlama dili, eşzamanlılık ve paralelleştirme konusunda oldukça yetenekli bir programlama dilidir. Bu dili kullanarak, birden fazla işlemi aynı anda çalıştırmak mümkündür. Bunun için C++'ta Thread kütüphanesi kullanılır. Thread kullanımı, kodunuzun yalnızca tek bir işlemci çekirdeğinde çalışmasını sağlamak yerine, birden fazla işlemci çekirdeğinde çalışmasına olanak tanır.
Bununla birlikte, C++'ta paralelleştirme yapmak için Thread kullanımından başka birkaç yöntem daha mevcuttur. C++11'den beri, bu dilde "Parallel STL" olarak bilinen yeni bir özelliğin geliştirildiği bilinmektedir. Parallel STL, standart STL kütüphanesinin bir uzantısıdır ve işlemleri paralel olarak yürütmek için kullanılır. Böylece, kodunuzun daha hızlı çalışmasını sağlamanın yanı sıra, performansını da artırabilirsiniz.
C++ Eşzamanlılık ve Paralelleştirme Yöntemleri |
---|
Thread kullanımı |
Parallel STL kullanımı |
Atomic Smart Pointer kullanımı |
- Thread kullanımı, birden çok iş parçacığının simultane olarak çalışmasını sağlayan en temel yöntemdir.
- Parallel STL, kodun daha hızlı ve verimli çalışmasına olanak tanıyan bir özelliktir. Standart STL kütüphanesinin bir uzantısıdır ve işlemleri paralel olarak yürütmek için kullanılır.
- Atomic Smart Pointer, birden çok iş parçacığının aynı bellek alanlarına erişmesini ve bu nedenle "data races" adı verilen hataların oluşmasını engelleyebilen bir özelliktir.
C++ programlama dilinde eşzamanlılık ve paralelleştirme yapmak oldukça güçlü ve verimli bir yöntemdir. Bu yöntemleri kullanarak, kodunuzun daha hızlı ve verimli çalışmasını sağlayabilirsiniz.
Thread kullanımı
C++ programlama dilinde eşzamanlı işlem yapmanın en temel yolu thread kullanımıdır. Thread, bir işlemi birden fazla parçaya bölerek işlemin eşzamanlı hale getirilmesini sağlar. Bu sayede, birden fazla fonksiyon aynı anda çalışabilir ve işlem süresi kısalır.
Thread kullanımı için C++ 11 ile birlikte std::thread adında bir sınıf tanıtıldı. Bu sınıf sayesinde, işlevsel iş parçacıkları oluşturmak ve bunları eşzamanlı olarak çalıştırmak mümkün hale geldi. Aşağıdaki kod örneğinde, iki fonksiyon aynı anda çalıştırılıyor:
#include <iostream>#include <thread>void Fonksiyon1() { std::cout << "İş Parçacığı 1 çalışıyor\n";}void Fonksiyon2() { std::cout << "İş Parçacığı 2 çalışıyor\n";}int main() { std::thread t1(Fonksiyon1); std::thread t2(Fonksiyon2); t1.join(); t2.join(); return 0;}
Yukarıdaki örnekte, Fonksiyon1 ve Fonksiyon2 fonksiyonları aynı anda çalıştırılmak üzere iki adet iş parçacığına atanıyor. t1.join(); ve t2.join(); satırları sayesinde, iş parçacıklarının tamamlanması bekleniyor.
Thread kullanımında dikkat edilmesi gereken bazı detaylar vardır. Örneğin, farklı iş parçacıkları aynı anda aynı değişkene erişirse data race oluşabilir. Bu durumun önüne geçmek için mutex ve atomic değişkenler gibi senkronizasyon araçları kullanılabilir.
Genel olarak, thread kullanımı C++'ta eşzamanlı işlemler yapmanın temel yollarından biridir ve birçok projede kullanılır.
Parallel STL
Parallel STL, paralel hesaplama için geliştirilen bir C++ kütüphanesidir. Bu kütüphane, C++11'den beri kullanımdadır ve C++ geliştiricilerine, STL algoritmlerini paralel olarak çalıştırmalarını sağlayarak çoklu iş parçacığı ortamlarında işlem yapmalarına olanak tanır.
Parallel STL, C++ geliştiricilerine işlem yüklerini paralelleştirmek için iki yol sunar. İlki, yüksek seviyeli arabirimlerin kullanımıdır. Diğeri ise düşük seviyeli C++ thread arabirimlerini kullanmaktır.
Parallel STL, birden fazla iş parçacığı kullanan işlemler için uygun görevleri otomatik olarak ayırır ve ardından bu görevleri belirli bir işlem sayısına bölerek parçalar. Bu sayede, her bir iş parçacığı ayrı bir görevi gerçekleştirebiliyor ve işlem hızı artırılıyor.
Bunun yanı sıra, C++ geliştiricileri Parallel STL kullanarak birçok operasyonu kolayca gerçekleştirebilirler. Örneğin, partial_sum veya sort gibi algoritmalar, Parallel STL ile birlikte paralel olarak çalıştırılabilir ve işlem hızı artırılabilir.
Parallel STL ile gelen bir diğer fayda, kullanıcının yaptığı hataları otomatik olarak belirleyen bir hata ayıklama aracıdır. Bu sayede, geliştiriciler kodlarını daha hızlı ve daha güvenli bir şekilde paralelleştirebilirler.
Partial Sum Örneği
Parallel STL kütüphanesi, C++'ın standart kütüphanesinin bir parçasıdır ve eşzamanlılık ve paralelleştirme işlemlerinin yapılabileceği bir arayüz sunar. Partial Sum örneği, Parallel STL'yi kullanarak bir hesaplama yapmayı ve sonuçları toplamayı işleyen bir örnektir.
Partial sum işlemi, birden çok sayı dizisinin elemanlarının toplamlarının hesaplanmasını sağlar. Bu çeşit işlemler, özellikle büyük boyutlu matrisler üzerinde çalışmak için yazılımcılarına önemli faydalar sunar. Parallel STL'in partial sum kullanarak bu örneği gerçekleştirmesi oldukça kolaydır.
Bir örnekle açıklamak gerekirse, eğer bir sayı dizimiz olsun ve Parallel STL kütüphanesi içindeki partial sum fonksiyonunu kullanarak bu dizinin elemanlarının toplamlarını hesaplamak istiyorsak, öncelikle sayı dizimizi bir vector içerisinde tutmamız gerekiyor.
Kod Örneği |
---|
std::vector<int> numbers { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; std::vector<int> partial_sum(numbers.size()); std::partial_sum(std::execution::par, numbers.begin(), numbers.end(), partial_sum.begin()); int total_sum = std::accumulate(partial_sum.begin(), partial_sum.end(), 0); |
Bu kod parçasını incelediğimizde, ilk olarak sayı dizimizi bir vector içinde tanımladık. Daha sonra, partial_sum isimli bir vector oluşturarak boyutunu ilk vectorumuzla aynı tuttuk. Ardından, Parallel STL kütüphanesi içindeki partial sum fonksiyonunu kullanarak sayı dizimizdeki elemanların toplamlarını alarak, partial_sum vectorümüzün içine yazdırdık. Son olarak, toplamların toplamını hesaplamak için accumulate fonksiyonunu kullandık.
Böylece Parallel STL kütüphanesindeki partial sum fonksiyonunu kullanarak sayı dizilerinin elemanlarının toplamlarını hesaplamak oldukça kolay ve hızlı hale gelir. Bu örnek, C++'ta eşzamanlılık ve paralelleştirme işlemlerinin mümkün olduğunu ve Parallel STL kütüphanesinin bu işlemleri kolaylaştırdığını göstermektedir.
Sort Örneği
Parallel STL, çok çekirdekli sistemlerin özelliklerinden faydalanarak C++ algoritma performansını önemli ölçüde artırmak için geliştirilmiştir. Bunun bir örneği olarak sort algoritması gösterilebilir.
Parallel STL'in sort fonksiyonu, standart sort fonksiyonu ile aynı parametrelere sahiptir. Ancak, sort fonksiyonunun birinci parametresi bir başlangıç noktasıdır ve ikinci parametresi bir bitiş noktasıdır. Başka bir deyişle, sıralanan dizinin sınırlarının işaretlenmesi gerekmektedir.
Bir örnekle açıklamak gerekirse, bir vektörün elemanlarını azalan sırada sıralamak istediğimizi varsayalım. Sort fonksiyonu kullanılırken, önce vektörün başlangıç noktası ve sonrasında vektörün bitiş noktası fonksiyona parametre olarak verilir.
Örnek Kod |
---|
#include <algorithm>#include <vector>#include <iostream>int main(){ std::vector<int> v = { 5, 2, 8, 1, 3, 9, 4, 6, 7 }; std::sort(std::execution::par, v.begin(), v.end(), std::greater<int>()); for (int i : v) { std::cout << i << " "; } return 0;} |
Parallel STL ile sort fonksiyonu birinci parametre olarak std::execution::par, ikinci parametre olarak vektörün başlangıç noktası, üçüncü parametre olarak vektörün bitiş noktası ve sonuncu parametre olarak da sıralama işleminin gerçekleştirileceği kriteri alacaktır. Yukarıdaki örnekte, sıralama işlemi vektörün elemanlarının büyüklüklerine göre gerçekleştirilmiştir. Çıktı olarak, "9 8 7 6 5 4 3 2 1" elde edilir. |
Sort fonksiyonunun kullanımı oldukça kolaydır ve algoritmanın optimizasyonu sağlamıştır. Özellikle büyük veri setleriyle çalışırken, sort fonksiyonunun parallel kullanımı işlem süresinde önemli bir azalma sağlayacaktır.
Data Races
Data races, programlama dillerindeki eşzamanlılık ve paralelleştirme tekniklerinden kaynaklanan sorunlardan biridir. Birçok thread veya iş parçacığı, ortak verilere erişebilir. Eş zamanlı olarak yapılan işlemlerde bu nedenle ortak verilerin güncellenmesi ve okunması sırasında hatalar oluşabilir. Bu hatalara "data race" adı verilir.
Data races, programda istenmeyen sonuçlara neden olarak hata ayıklama sürecini oldukça zorlaştırır. Bu nedenle eş zamanlılık ve paralelleştirme teknikleri kullanılırken data races önlenmelidir. Bunun için bazı teknikler kullanılabilir.
Birinci teknik, bölümlemeyi kullanmaktır. Bölümleme, belirli bir veri satırına ya da değişkene sadece bir iş parçacığı ya da thread'in erişmesine izin verir. Bu teknik, data race'in önüne geçmeyi sağlar. Ancak sıralama işlemlerinde zaman kaybı yaşanabilir.
İkinci teknik, mutex ve semaphore kullanmaktır. Mutex ve semaphore, bir iş parçacığına erişim verilmeden önce belirli bir koşulun sağlanması gerektiği anlamına gelir. Bu teknikler sayesinde eş zamanlı erişimler sıraya alınarak hata alınan işlemler önlenir.
Üçüncü teknik ise atomik işlemlerdir. Atomik işlemler, bir işlem atomik hale getirilerek, bir iş parçacığı işlemi döndürmeden başka iş parçacıkları o işleme müdahale edemez. Bu teknik, sıralama işlemlerinde zaman kaybı yaşanmasının önüne geçer.
Data race'ler, programlamada oldukça ciddi sorunlar yaratabileceği için eş zamanlılık ve paralelleştirme teknikleri kullanırken data race'lerin önüne geçmek oldukça önemlidir.
C++20'deki Güncellemeler
C++20, C++'in son sürümüdür ve içeriğinde birçok yenilik barındırmaktadır. Bu yenilikler ile C++ daha modern ve güçlü bir dil haline gelmiştir. C++20 ile gelen yeniliklerden bazıları şunlardır:
- Concepts: Konseptler, C++'da bellek yönetimini geliştirmek için kullanılan bir yapıdır. Konseptler, programcının bir nesnenin özelliklerini önceden belirlemesine izin verir ve böylece hataları önler.
- Modules: Modüller, C++ programlarının daha hızlı çalışmasını sağlayan bir yapıdır. Modüller birimleri dışa açığa çıkarmadan önce derlenir ve böylece derleme süresini azaltır.
- Coroutine Kavramı: Coroutine, C++20 ile birlikte gelen bir kavramdır. Coroutine, iş parçacıkları gibi birden çok eşzamanlı işi çalıştırmak için kullanılan bir yapıdır. Coroutine, kodun daha okunaklı ve anlaşılır hale gelmesine yardımcı olur.
- Atomic Smart Pointer: Atomic smart pointer, C++20 ile birlikte gelen bir güncellemedir. Bu yapı, önceki smart pointerlardan farklı olarak thread-safe özelliklere sahip bir yapıdır. Bu özellikler sayesinde, birden fazla iş parçacığına sahip bir uygulamada, bellek sızıntıları gibi sorunlar yaşanmadan bellek yönetimi yapılabilir.
C++20 ile birlikte daha birçok yenilik gelmiştir ve bu yenilikler dilin hem hız hem de güçlülük açısından daha da gelişmesini sağlamıştır. Programcılar C++20'nin sunduğu olanaklarla daha verimli ve esnek kodlar yazabilirler.
Coroutine Kavramı
C++20 ile birlikte gelen en önemli yeniliklerden biri coroutine kavramıdır. Coroutine'lar, bir işletim sistemi thread'inden çok daha hafif bir yol sağlar. Coroutine'lar, bir işlemi yaparken ara verip daha sonra kaldıkları yerden devam etmek için kullanılabilirler. Bu, örneğin bir dosya çıktısı beklerken programın diğer işlerle ilgilenmesine izin verebilir.
C++20'deki coroutine kavramı, co_await anahtar kelimesinin kullanımıyla birlikte gelir. Bu anahtar kelime, bir işlemin tamamlanmasını beklerken coroutine'i duraklatmak için kullanılır. Bu bekleme sırasında, kaynaklar farklı bir işlem için kullanılabilir. Belekleme süresi bittiğinde coroutine, co_return anahtar kelimesiyle bitirilir.
Coroutine kavramı, modern C++ kodlarında oldukça yaygın hale geldi. Bunu kullanarak, iş parçacıkları ile aynı derecede hızlı olabilir ve daha az kaynak tüketebilirsiniz. Coroutine kavramı ile birlikte C++20, birçok işlemi daha acısız hale getiren bir dizi yeni özellikle birlikte gelir.
Atomic Smart Pointer
Atomic smart pointer, C++'ta C++11 ve sonraki sürümlerde yer alan bir özelliktir. Normal smart pointer'lar, bir heap alanındaki nesneleri izlemek ve silmek için kullanılır. Ancak birden fazla threadin aynı anda aynı smart pointer objesine erişmesi durumunda bu durum data races oluşturabilir. Atomic smart pointer, aynı anda birden fazla thread üzerinde çalışırken data races oluşmasını engeller.
Atomic smart pointer aynı zamanda slab allocation'ı kullanarak daha hızlı çalışır. Bu teknik sayesinde, kendi algoritmalarını veya belirli bir bellek yönetim sistemini kullanmak yerine, sheap bellek için ayrılmış büyük bir havuzda nesneleri oluşturur. Atomic smart pointer aynı zamanda daha güvenilir bir performans sağlar ve daha az bellek tüketir.
Atomic smart pointer'ın diğer farklı özelliği de thread safe bir arabirim sağlamasıdır. Bu özellik sayesinde, thread'ler arasında değişkenlerin paylaşımı sırasında data races engellenir. Atomic smart pointer, ilgili bellek yöneticisine ihtiyaç duymadan nesneleri izler ve siler, böylece performansın daha iyi olmasını sağlar.
Normal Smart Pointer | Atomic Smart Pointer |
---|---|
Birden fazla threadin aynı smart pointer objesine erişmesi data races oluşmasına sebep olabilir | Data races oluşmasını engeller |
Bellek tüketimi fazladır | Daha az bellek tüketir |
Thread safe değildir | Thread safe bir arabirim sağlar |
Atomic smart pointer, C++'taki thread'ler için hızlı, güvenli, ve verimli bir bellek yönetim sistemidir. Normal smart pointer'larla karşılaştırıldığında oldukça farklı bir yapıya sahiptir ve özellikle paralel programlamada oldukça etkilidir. Daha önceleri oluşmuş data races problemlerini en aza indirir ve daha iyi bir performans sağlar.