Nếu tôi gặp tình huống sau:
bool cond_var;
#pragma omp được chia sẻ song song(cond_var)
{
bool some_private_var;
// ...
LÀM {
#pragma omp đơn
{
cond_var = đúng;
}
// làm gì đó, tính toán some_private_var;
// ...
#pragma omp cập nhật nguyên tử
cond_var &= some_private_var;
// Bước đồng bộ hóa
// (???)
} while(cond_var);
// ... (những thứ song song khác)
}
Tôi muốn vòng lặp do-while của mình có cùng số lần lặp cho tất cả các luồng của mình, nhưng khi tôi cố gắng #rào cản pragma omp
Khi thực hiện điều này như một bước đồng bộ hóa (ngay trước khi kết thúc vòng lặp), tôi gặp phải tình trạng bế tắc. In cond_var
Giá trị cho thấy một số chủ đề coi nó như ĐÚNG VẬY
trong khi các chủ đề khác coi nó là SAI
, do đó vòng lặp hoàn thành một số, khiến những phần khác bị mắc kẹt ở hàng rào. Sau đó tôi đã cố gắng rào cản
Và tuôn ra
nhiều sự kết hợp và trình tự khác nhau, nhưng không thành công (với một số sự kết hợp, sự bế tắc đã bị trì hoãn).
Làm cách nào tôi có thể kết hợp và đồng bộ hóa chính xác các điều kiện vòng lặp giữa các luồng để tất cả các vòng lặp có cùng số lần lặp?
gia hạn
Tôi cũng đã thử sử dụng #pragma đọc nguyên tử
Sẽ cond_var
Tải giá trị vào một biến riêng tư khác và kiểm tra điều kiện. Nó cũng không hoạt động. Rõ ràng, các lần đọc nguyên tử đảm bảo rằng tôi có một giá trị nhất quán (cũ hoặc mới), nhưng không đảm bảo rằng nó được cập nhật.
更新 2
Dựa trên mã của Jonathan Dursi, đây là mã trông giống với những gì tôi đang cố gắng thực hiện với MVCE:
#include
#include
#include
#include
#include
int chính() {
bool cond_var;
const int nthreads = omp_get_max_threads();
#pragma omp song song mặc định (none) được chia sẻ (cond_var)
{
bool some_private_var;
std::random_devicerd;
std::mt19937 rng(rd());
iter_count không dấu = 0;
/* khả năng phải kết thúc: 1 trong 6**nthreads; tất cả các chủ đề phải chọn 0 */
std::uniform_int_distribution xúc xắc(0,5);
const int tid = omp_get_thread_num();
printf("Chủ đề %d đã bắt đầu.\n", tid);
LÀM {
++iter_count;
#pragma omp một lần được chia sẻ(cond_var)
{
// cond_var phải được đặt lại thành 'true' vì nó là
// phần tử trung hòa của &
// Để vòng lặp kết thúc, tất cả các thread phải chọn
// cùng giá trị ngẫu nhiên 0
cond_var = đúng;
}
some_private_var = (xúc xắc(rng) == 0);
// Nếu tất cả thread chọn 0, cond_var sẽ vẫn là 'true', kết thúc vòng lặp
#pragma omp cập nhật nguyên tử
cond_var &= some_private_var;
#rào cản pragma omp
} while(!cond_var);
printf("Thread %d đã hoàn thành với %u lần lặp.\n", tid, iter_count);
}
return 0;
}
Chạy 8 luồng trên một máy có đủ lõi logic để chạy tất cả chúng đồng thời, hầu hết chạy bị bế tắc ở lần lặp đầu tiên, mặc dù một lần chạy đã hoàn thành chính xác ở lần lặp thứ hai (không đáp ứng cơ hội 1 trong 1 1679616 (6**8) Tất cả các luồng chọn 0).
Vấn đề là trong vòng lặp while, bạn cập nhật cond_var hai lần và sử dụng nó lần thứ ba, đồng thời bạn cần đảm bảo các thao tác này không ảnh hưởng lẫn nhau. Mỗi lần lặp, mã:
- Đặt cond_var = true (sử dụng pragma OpenMP không tồn tại, "một lần", nó bị bỏ qua và hoàn thành trên mỗi luồng)
- Cập nhật cond_var bằng cách sử dụng biến điều kiện cục bộ&ing;
- Sử dụng cond_var được mọi người cập nhật để kiểm tra xem có thoát khỏi vòng lặp hay không.
Do đó, bạn cần đảm bảo rằng một luồng không được đặt cond_var thành true (1) trong khi các luồng khác đang đặt nó (2); rằng không có luồng nào vẫn chạy (2) khi sử dụng nó để kiểm tra bên ngoài vòng lặp (3); rằng không có luồng nào đang kiểm tra It(3) trong khi luồng đang đặt nó thành true(1).
Cách rõ ràng để làm điều này là đặt một rào cản giữa mỗi tình huống trong số ba tình huống này - tức là ba rào cản. Vì vậy, điều này hoạt động:
#include
#include
#include
#include
#include
int chính() {
bool cond_var;
#pragma omp mặc định song song (none) được chia sẻ(cond_var,std::cout)
{
bool some_private_var;
std::random_devicerd;
std::mt19937 rng(rd());
iter_count không dấu = 0;
std::uniform_int_distribution xúc xắc(0,1);
const int tid = omp_get_thread_num();
printf("Chủ đề %d đã bắt đầu.\n", tid);
LÀM {
++iter_count;
#rào cản pragma omp
#pragma omp đơn
cond_var = đúng;
// rào cản ngầm ở đây sau khi tắt bằng mệnh đề nowai.
some_private_var = (xúc xắc(rng) == 0);
// Nếu tất cả thread chọn 0, cond_var sẽ vẫn là 'true', kết thúc vòng lặp
#pragma omp cập nhật nguyên tử
cond_var &= some_private_var;
#rào cản pragma omp
} while(!cond_var);
#pragma omp quan trọng
std::cout << "Thread " << tid << " đã kết thúc với các lần lặp " << iter_count << "."
}
return 0;
}
Bạn có thể làm tốt hơn một chút và yêu cầu mỗi luồng chỉ đặt một biến cục bộ trong mảng dùng chung, sau đó yêu cầu một luồng thực hiện thao tác AND; vì vậy bạn vẫn cần hai rào cản, một để đảm bảo mọi người đều hoàn thành trước khi giải quyết và một rào cản còn lại là để đảm bảo rằng việc giải quyết được thực hiện trước khi thử nghiệm hoàn tất:
#include
#include
#include
#include
#include
int chính() {
bool cond_var;
const int num_threads = omp_get_max_threads();
const unsigned int interval=64/sizeof(bool); /* để tránh chia sẻ sai */
bool local_cond_var[num_threads*spacing];
#pragma omp mặc định song song (none) được chia sẻ(cond_var,std::cout,local_cond_var)
{
std::random_devicerd;
std::mt19937 rng(rd());
iter_count không dấu = 0;
std::uniform_int_distribution xúc xắc(0,1);
const int tid = omp_get_thread_num();
printf("Chủ đề %d đã bắt đầu.\n", tid);
LÀM {
++iter_count;
local_cond_var[tid*spacing] = (xúc xắc(rng) == 0);
#rào cản pragma omp
#pragma omp đơn
{
cond_var = đúng;
cho (int i=0; i
cond_var &= local_cond_var[i*spacing];
}
// rào cản ngầm ở đây sau khi tắt bằng mệnh đề nowai.
} while(!cond_var);
#pragma omp quan trọng
std::cout << "Thread " << tid << " đã kết thúc với các lần lặp " << iter_count << "."
}
return 0;
}
Lưu ý rằng các rào cản, dù rõ ràng hay ngầm định, có nghĩa là các biến dùng chung sẽ bị xóa và việc thêm mệnh đề nowait vào một mệnh đề đơn có thể gây ra bế tắc không liên tục.
Tôi là một lập trình viên xuất sắc, rất giỏi!