2014-11-18 12 views
5

Sayıları bir diziye eklemek için OpenMP kullanmayı deniyorum.OpenMP'de veri yarışıyla nasıl baş edebilirim?

int* input = (int*) malloc (sizeof(int)*snum); 
    int sum = 0; 
    int i; 
    for(i=0;i<snum;i++){ 
     input[i] = i+1; 
    } 
    #pragma omp parallel for schedule(static) 
    for(i=0;i<snum;i++) 
    { 
     int* tmpsum = input+i; 
sum += *tmpsum; 
    } 

Bu sum için doğru sonucu vermez: Aşağıdaki benim kodudur. Sorun nedir?

+2

'sum' bir * azaltma * değişkeni olmalıdır,' redüksiyon (+: toplam) ' –

cevap

8

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 = 11 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.

+1

Doğru kelime" _threads_ "olurken, _process_ kullandığınız cevabınızda oldukça fazla yer vardır. Bu karışıklığı önlemek için bunu düzeltmek isteyebilirsiniz. –

+0

@HristoIliev: Righto. Şu anda bir MPI kodu yazıyorum, bu yüzden bütün gün süreçler açısından düşünüyorum; bu yüzden karışım. Şimdi sabit, teşekkürler. – wolfPack88

+0

cevabınız için teşekkürler, ve eğer var toplamı bu "int sum [2]" gibi bir dizi ise #pragma omp redüksiyonunu (+: sum) ve #pragma omp redüksiyonunu (+: sum [0]) kullandım. # pragma omp azaltma (+: toplam [1]), işe yaramıyor! ne yapabilirim? – YOung

3

Kullanım reduction fıkra (description at MSDN).

int* input = (int*) malloc (sizeof(int)*snum); 
int sum = 0; 
int i; 
for(i=0;i<snum;i++){ 
    input[i] = i+1; 
} 
#pragma omp parallel for schedule(static) reduction(+:sum) 
for(i=0;i<snum;i++) 
{ 
    sum += input[i]; 
} 
İlgili konular