我正在研究 OpenMP 并撰寫了振動篩排序的實作。這里有2個連續的回圈,為了讓它們被順序呼叫,我以omp_init_lock,omp_destroy_lock的形式添加了阻塞器,但結果仍然不正確。請告訴我如何并行化兩個連續的周期。我的代碼如下:
int Left, Right;
Left = 1;
Right = ARR_SIZE;
while (Left <= Right)
{
omp_init_lock(&lock);
#pragma omp parallel reduction( :Left) num_threads(4)
{
#pragma omp for
for (int i = Right; i >= Left; i--) {
if (Arr[i - 1] > Arr[i]) {
int temp;
temp = Arr[i];
Arr[i] = Arr[i - 1];
Arr[i - 1] = temp;
}
}
Left ;
}
omp_destroy_lock(&lock);
omp_init_lock(&lock);
#pragma omp parallel reduction( :Right) num_threads(4)
{
#pragma omp for
for (int i = Left; i <= Right; i ) {
if (Arr[i - 1] > Arr[i]) {
int temp;
temp = Arr[i];
Arr[i] = Arr[i - 1];
Arr[i - 1] = temp;
}
}
Right--;
}
omp_destroy_lock(&lock);
}
uj5u.com熱心網友回復:
omp for如果迭代是獨立的,你只能做一些事情。你的顯然不是。- 你的鎖沒有任何用處。兩個平行區域總是按順序完成。因此,您可以卸下鎖。
uj5u.com熱心網友回復:
您似乎對 OpenMP 的作業原理有幾個誤解。
- 兩個并行部分不并行執行。這是 fork-join 并行性。并行部分本身由多個執行緒執行,然后在并行部分的末尾重新加入。
您的代碼看起來像您期望的那樣作業pragma omp sections。旁注:除非您絕對沒有其他選擇和/或您確切知道自己在做什么,否則不要使用部分。它們不能很好地擴展。
- 您使用 lock API 是錯誤的。
omp_init_lock初始化一個鎖物件。它沒有獲得它。同樣,destroy 函式會釋放它,它不會釋放鎖。如果您想獲得一個鎖,請在進入并行部分之前使用您初始化一次的鎖omp_set_lock。omp_unset_lock
一般來說,如果您需要為代碼的擴展部分加鎖,它不會并行化。閱讀阿姆達爾定律。鎖只有在很少使用或者兩個執行緒同時競爭同一個鎖的可能性很低的情況下才有用。
您的代碼包含競爭條件。由于您使用
pragma omp for了 ,因此兩個不同的執行緒可能會同時執行第 i 次和第 (i-1) 次迭代。這意味著它們將觸及相同的整數。這是未定義的行為,可以說會導致他們踩到對方的腳趾。我不知道你想用這些減少做什么。
如何解決這個問題
好吧,傳統的振動器排序不能并行作業,因為在外回圈的一次迭代中,一個元素可能會移動整個距離到范圍的末尾。這需要大量不可行的執行緒間協調。
您可以做的是冒泡排序的一種變體,其中每個執行緒查看兩個值并交換它們。來回移動此視窗,值將緩慢移動到正確位置。
這應該有效:
#include <utility>
// using std::swap
void shake_sort(int* arr, int n) noexcept
{
using std::swap;
const int even_to_odd = n / 2;
const int odd_to_even = (n - 1) / 2;
bool any_swap;
do {
any_swap = false;
# pragma omp parallel for reduction(|:any_swap)
for(int i = 0; i < even_to_odd; i) {
int left = i * 2;
int right = left 1;
if(arr[left] > arr[right]) {
swap(arr[left], arr[right]);
any_swap = true;
}
}
# pragma omp parallel for reduction(|:any_swap)
for(int i = 0; i < odd_to_even; i) {
int left = i * 2 1;
int right = left 1;
if(arr[left] > arr[right]) {
swap(arr[left], arr[right]);
any_swap = true;
}
}
} while(any_swap);
}
注意你不能排除左右邊界,因為一個外部迭代不能保證那里的值是正確的。
其他備注:
- 其他人已經評論了如何
std::swap使代碼更具可讀性 - 您無需指定
num_threads. OpenMP 可以自己解決這個問題
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/481903.html
上一篇:佇列如何解決執行緒競爭問題?
下一篇:可重入鎖是物件級鎖還是類級鎖?
