Fungsi dependensi openMP

Nov 24 2020

Saya memiliki 5 fungsi A, B, C, D, E.

Untuk mengeksekusi DI perlu B, C untuk dieksekusi, untuk mengeksekusi EI perlu A, D untuk dieksekusi.

Saya sudah mencoba ini

int main()
{
    #pragma omp parallel num_threads(5) 
    {
        long t1 = clock();
        int a = 0, b = 0, c = 0, d = 0, e = 0;
        int th = omp_get_thread_num();
        if (th == 0) {
            a += A();
            printf("A is finished after %d\n", clock() - t1);
        }
        if (th == 1) {
            b += B();
            printf("B is finished after %d\n", clock() - t1);
        }
        if (th == 2) {
            c += C();
            printf("C is finished after %d\n", clock() - t1);
        }
        if (th == 3 && (b == 1 && c == 1)) {
            d += D();
            printf("D is finished after %d\n", clock() - t1);
        }
        if (th == 4 && (a == 1 && d == 1)) {
            e += E();
            printf("E is finished after %d\n", clock() - t1);
        }

    }
    return 0;
}

tapi D, E belum dieksekusi

Semua fungsi ini mengembalikan 1 hingga sekarang untuk tujuan debugging

Jawaban

1 dreamcrash Nov 24 2020 at 16:58

Variabel a, b, cdan d,tidak dapat digunakan untuk berkomunikasi antara benang karena mereka semua pribadi . Karenanya, setiap utas memiliki salinan pribadinya sendiri. Selain itu, biasanya bukan ide yang baik untuk menggunakannya untuk tujuan sinkronisasi.

Dalam kode Anda thread=3tidak akan pernah menunggu if (th == 3 && (b == 1 && c == 1))karena:

  1. bdan cbersifat pribadi, jadi thread=3has b=0dan c=0terlepas dari apa yang telah dilakukan utas lain pada salinan variabel b=0dan c=0.
  2. Tidak ada yang memberi tahu utas itu untuk menunggu ( mis., Beberapa konstruktor serupa sinkronisasi).

Jika Anda ingin utas menunggu satu sama lain, gunakan omp barrier. Semua utas harus memanggil penghalang sebelum mereka dapat melanjutkan komputasi mereka.

 int main()
    {
        #pragma omp parallel num_threads(5) 
        {
            long t1 = clock();
            int a = 0, b = 0, c = 0, d = 0, e = 0;
            int th = omp_get_thread_num();
            if (th == 0) {
                a += A();
                printf("A is finished after %d\n", clock() - t1);
            }
            if (th == 1) {
                b += B();
                printf("B is finished after %d\n", clock() - t1);
            }
            if (th == 2) {
                c += C();
                printf("C is finished after %d\n", clock() - t1);
            }
            // Threads will wait for each other here
            #pragma omp barrier 
            if (th == 3) {
                d += D();
                printf("D is finished after %d\n", clock() - t1);
            }
            // Threads will wait for each other here
            #pragma omp barrier 
            if (th == 4) {
                e += E();
                printf("E is finished after %d\n", clock() - t1);
            }
        }
        return 0;
    }

Pendekatan yang lebih canggih adalah menggunakan tugas dengan dependensi fitur yang dirilis pada standar OpenMP 4.0. Sudah ada penjelasan bagus tentang cara kerja fitur ini di utas ini.

int a = 0, b = 0, c = 0, d = 0, e = 0;
#pragma omp parallel num_threads(5) shared(a, b, c, d)
{
  #pragma omp single nowait
  {
      long t1 = clock();

      int th = omp_get_thread_num();
      #pragma omp task  depend (out:a) 
      {
          a += A();
          printf("A is finished after %d\n", clock() - t1);
      }
      #pragma omp task depend (out:b) 
      {
         b += B();
         printf("B is finished after %d\n", clock() - t1);
      }
      #pragma omp task depend (out:c) 
      { 
          c += C();
          printf("C is finished after %d\n", clock() - t1);
      }
     #pragma omp task depend (in:a, b) depend(out:d) 
     {
        d += D(); 
        printf("D is finished after %d\n", clock() - t1);
     }
     #pragma omp task depend (in:a, b)  
     {
       e += E();
       printf("E is finished after %d\n", clock() - t1);
     }
  }
}
return 0;
}
2 HristoIliev Nov 24 2020 at 17:43

Solusi OpenMP yang tepat adalah menggunakan tugas dengan dependensi data:

    #pragma omp parallel num_threads(3)
    #pragma omp single
    {
        double t1 = omp_wtime();
        int a = 0, b = 0, c = 0, d = 0, e = 0;
        #pragma omp task shared(a) depend(out: a)
        {
            a += A();
            printf("A is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(b) depend(out: b)
        {
            b += B();
            printf("B is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(c) depend(out: c)
        {
            c += C();
            printf("C is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(b,c,d) depend(in: b,c) depend(out: d)
        {
            d += D();
            printf("D is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(a,d,e) depend(in: a,d)
        {
            e += E();
            printf("E is finished after %f\n", omp_wtime() - t1);
        }

    }

Di sini, tugas Aditandai sebagai produser untuk nilai adengan depend(out: a)dan tugas Dditandai sebagai produsen ddengan depend(out: d). Tugas Editandai sebagai konsumen dari dua nilai tersebut dengan depend(in: a,d). Mengikuti dependensi output (produser) dan input (konsumen), runtime OpenMP membangun DAG eksekusi (grafik asiklik terarah) yang memberi tahu urutan eksekusi yang tepat dari semua tugas. Anda juga tidak membutuhkan lima utas - tiga sudah cukup.

Memiliki kode penugasan di dalam singlekonstruksi adalah OpenMP yang sangat idiomatis.

Dependensi tugas diperkenalkan oleh OpenMP 4.0 pada tahun 2013, jadi compiler modern apa pun kecuali MSVC ++ harus menyediakan dukungan untuk fitur tersebut.