Kodunuz şu anda sonuç yanlıştır, bu yüzden de bir race condition sahiptir.
Sen 2 parçacığı üzerinde çalışan ve dizi int input[4] = {1, 2, 3, 4};
şudur: Bu yüzden göstermek için, basit bir örnek kullanalım. sum
'u 0
'a doğru şekilde başlatırsınız ve döngüyü başlatmak için hazırsınız. senin döngünün ilk yinelemesi olarak, iplik 0 ve iplik 1 0
olarak bellekten sum
okuyun ve sonra sum
için kendi elemanını ekleyin ve geri belleğe yazın. Bununla birlikte, bu iplik 0 iplik 1 belleğe sum = 2
yazmaya çalışıyor iken, bellek (birinci eleman sum = 0 + 1 = 1
1
ve) için sum = 1
yazmaya çalışıyor demektir (ikinci eleman 2
ve sum = 0 + 2 = 2
olan). Bu kodun son sonucu, iş parçacıklarının hangisinin sonunu bitirdiğine bağlıdır ve bu nedenle bir yarış koşulu olan son belleğe yazar. Sadece bu değil, bu özel durumda, kodun üretebileceği cevapların hiçbiri doğru değil! Bunu aşmanın birkaç yolu vardır;
#pragma omp critical
:
OpenMP olarak, bir critical
direktifi denir ne var ki ben üç temel yöntem aşağıda ayrıntılı olarak veriyoruz. Bu, kodu bir seferde yalnızca bir iş parçacığı tarafından yapılabilecek şekilde kısıtlar. Örneğin, for
-loop yazılabilir: sadece bir iplik erişir ve bir seferde sum
yazar olarak
#pragma omp parallel for schedule(static)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
#pragma omp critical
sum += *tmpsum;
}
Bu yarış durumu ortadan kaldırır. Ancak, critical
yönergesi, performans için çok kötüdür ve büyük olasılıkla, OpenMP'yi kullanarak elde ettiğiniz kazanımların büyük bir bölümünü (eğer olmasa da) öldürecektir.
#pragma omp atomic
:
atomic
direktif critical
yönergede çok benzer. En önemli fark, critical
yönergesinin, her seferinde bir iş parçacığı yapmak istediğiniz herhangi bir şeye uygulanırken, atomic
yönergesinin yalnızca bellek okuma/yazma işlemleri için geçerli olmasıdır. Bu kod örneğinde yapıyoruz tüm okuma ve toplamak için yazılı olduğu gibi, bu yönerge mükemmel çalışır:
#pragma omp parallel for schedule(static)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
#pragma omp atomic
sum += *tmpsum;
}
atomic
performansı critical
daha genel olarak önemli ölçüde daha iyidir. Ancak, özel durumunuzda hala en iyi seçenek değildir.
reduction
:
zaten başkaları tarafından ileri sürülmüştür kullanmanız gereken yöntem ve metot, reduction
olduğunu. Sen hiç for
-loop değiştirerek bunu yapabilirsiniz:
#pragma omp parallel for schedule(static) reduction(+:sum)
for(i = 0; i < snum; i++) {
int *tmpsum = input + i;
sum += *tmpsum;
}
reduction
komut döngü çalışırken, her iş parçacığı kendi sum
değişkenin kaydını tutar ve hepsini eklemek istiyorum, OpenMP söyler Döngünün sonunda. Bu, tüm döngünüzün artık paralel olarak çalıştığı en etkili yöntemdir, her bir iş parçacığının sum
değerlerinin eklenmesi gerektiğinde, döngünün ucundaki tek genel gider.
'sum' bir * azaltma * değişkeni olmalıdır,' redüksiyon (+: toplam) ' –