由於OpenMP 2.0沒有取消構造,因此您必須自行實施一個構件,例如通過使用共享變量。這也意味着您不能使用for
工作共享構造,因爲不允許打破並行循環(這就是OpenMP 4.0引入了取消構造的原因)。如果您在評估每個元素之間執行取消檢查,則可能會發生兩個或更多個線程找到與條件匹配的元素。因此,應該執行對指數形成分鐘還原:
int found = 0;
int first_index = INVALID_VALUE;
int iteration = 0;
#pragma omp parallel
{
int my_index = INVALID_VALUE;
int i;
do
{
// Later versions of OpenMP allow for "atomic capture"
// but OpenMP 2.0 requires a critical directive instead
#pragma omp critical(iteration)
{
i = iteration++;
}
if (i < N && check(i))
{
found = 1;
my_index = i;
}
} while (!found && i < N);
#pragma omp critical(reduction)
if (my_index != INVALID_VALUE)
{
if (first_index == INVALID_VALUE || my_index < first_index)
first_index = my_index;
}
// Only needed if more code follows before the end of the region
#pragma omp barrier
...
}
此代碼假定檢查第i個元素(check(i)
)的條件不改變元件的狀態,並且因此,最壞的可能發生的事情是找到匹配元素的線程可能不得不等待所有其他線程完成檢查他們當前正在工作的元素,並且等待時間將是所有處理時間的最大值。
do循環中使用的critical
構造是昂貴的。如果check()
並不需要太多時間,那麼你可以考慮用大塊的工作重複,而不是:
do
{
#pragma omp critical(chunk)
{
my_chunk = chunk++;
}
if (my_chunk >= N_chunks)
break;
for (i = my_chunk * chunk_size; !found && i < (my_chunk+1)*chunk_size; i++)
{
if (check(i))
{
found = 1;
my_index = i;
break;
}
}
} while (!found && my_chunk < N_chunks);
另一種解決方案,合理地發揮作用時,元件的數量並不大,並檢查每一個是昂貴的:
#pragma omp parallel
{
#pragma omp for schedule(dynamic,x)
for (i = 0; i < N; i++)
{
if (!found && check(i))
{
my_index = i;
found = 1;
}
}
// Min reduction from the solution above
...
}
一旦found
爲真,循環迭代的其餘部分將運行,因爲&&
的shortcutting屬性「空」的機構。
請注意,最好情況下的複雜度從0增加到N/K,其中N是元素的總數,K是線程數。 – rubenvb
這取決於元素的大小以及檢查條件需要多長時間。如果你正在對'std :: vector'做'=='這樣的簡單操作,那麼你不會像這樣交錯,因爲這會對緩存造成嚴重破壞。在這種情況下,您可能希望線程一次檢查整數塊。如果你的矢量對象是1MB一塊,並且需要1-2秒來執行檢查,那麼交錯可能更有意義。 –
RyanP
如果tbb呼籲您使用它。在Openmp中,如果我理解這個問題,那麼您將對數據進行分區,因爲您似乎已經使用內部搜索循環進行了分區,將內部結果合併到外部omp歸約firstprivate lastprivate或critical中。 – tim18