OpenMP phụ thuộc hàm
Tôi có 5 chức năng A, B, C, D, E.
Để thực hiện DI cần B, C được thực thi, để thực hiện EI cần A, D được thực hiện.
Tôi đã thử cái này
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;
}
nhưng D, E không thực hiện
Tất cả các hàm này trả về 1 cho đến bây giờ cho mục đích gỡ lỗi
Trả lời
Các biến a, b, cvà d,không thể được sử dụng để giao tiếp giữa các chủ đề, vì họ là tất cả các tin . Do đó, mỗi luồng có một bản sao riêng của chúng. Hơn nữa, thông thường không phải là một ý kiến hay nếu sử dụng chúng cho mục đích đồng bộ hóa.
Trong mã của bạn thread=3sẽ không bao giờ chờ đợi if (th == 3 && (b == 1 && c == 1))vì:
bvàclà riêng tư, vì vậythread=3cób=0vàc=0bất kể các luồng khác đã làm gì với các bản sao của chúng của các biếnb=0vàc=0.- Không có gì yêu cầu luồng đó phải chờ ( ví dụ: một số phương thức khởi tạo giống đồng bộ hóa).
Nếu bạn muốn các chủ đề đợi nhau, hãy sử dụng omp barrierthay thế. Tất cả các luồng sẽ phải gọi rào cản trước khi chúng có thể tiến hành tính toán của mình.
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;
}
Một cách tiếp cận phức tạp hơn sẽ là sử dụng các tác vụ có phụ thuộc, một tính năng được phát hành trên tiêu chuẩn OpenMP 4.0. Đã có một lời giải thích hay về cách hoạt động của tính năng này trên chủ đề này.
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;
}
Một giải pháp OpenMP thích hợp sẽ là sử dụng các tác vụ với các phụ thuộc dữ liệu:
#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);
}
}
Ở đây, nhiệm vụ Ađược đánh dấu là nhà sản xuất cho giá trị của avới depend(out: a)và nhiệm vụ Dđược đánh dấu là nhà sản xuất của dvới depend(out: d). Nhiệm vụ Eđược đánh dấu là người tiêu dùng của hai giá trị đó với depend(in: a,d). Theo sau các phụ thuộc đầu ra (nhà sản xuất) và đầu vào (người tiêu dùng), thời gian chạy OpenMP xây dựng một DAG thực thi (đồ thị xoay chiều có hướng) cho nó biết thứ tự thực hiện thích hợp của tất cả các tác vụ. Bạn cũng không cần năm chủ đề - ba là đủ.
Có mã tác vụ bên trong một singlecấu trúc là OpenMP rất dễ hiểu.
Các phụ thuộc tác vụ đã được OpenMP 4.0 giới thiệu vào năm 2013, vì vậy bất kỳ trình biên dịch hiện đại nào ngoại trừ MSVC ++ đều phải cung cấp hỗ trợ cho tính năng đó.