Sorting openmp中的shell排序
如果有人熟悉openmp,我没有得到排序列表。我做错了什么。我在最后使用了critical,所以在对该部分进行排序时,只有一个线程可以访问该部分。我想我的个人价值观是不正确的。他们应该在那里吗?还是我只需要“布拉格语omp”就好了Sorting openmp中的shell排序,sorting,openmp,shellsort,Sorting,Openmp,Shellsort,如果有人熟悉openmp,我没有得到排序列表。我做错了什么。我在最后使用了critical,所以在对该部分进行排序时,只有一个线程可以访问该部分。我想我的个人价值观是不正确的。他们应该在那里吗?还是我只需要“布拉格语omp”就好了 void shellsort(int a[]) { int i, j, k, m, temp; omp_set_num_threads(10); for(m = 2; m > 0; m = m/2) {
void shellsort(int a[])
{
int i, j, k, m, temp;
omp_set_num_threads(10);
for(m = 2; m > 0; m = m/2)
{
#pragma omp parallel for private (j, m)
for(j = m; j < 100; j++)
{
#pragma omp critical
for(i = j-m; i >= 0; i = i-m)
{
if(a[i+m] >= a[i])
break;
else
{
temp = a[i];
a[i] = a[i+m];
a[i+m] = temp;
}
}
}
}
}
void外壳排序(int a[]
{
int i,j,k,m,温度;
omp_设置_数量_线程(10);
对于(m=2;m>0;m=m/2)
{
#pragma omp并行专用(j,m)
对于(j=m;j<100;j++)
{
#pragma-omp-critical
对于(i=j-m;i>=0;i=i-m)
{
如果(a[i+m]>=a[i])
打破
其他的
{
温度=a[i];
a[i]=a[i+m];
a[i+m]=温度;
}
}
}
}
}
变量“j”和“i”需要在并行区域上声明为私有。就现在而言,我很惊讶任何事情都在发生,因为“m”不能是私人的。关键区域允许它为“i”循环工作,但是关键区域应该能够被缩减——尽管我已经有一段时间没有进行shell排序了。变量“j”和“i”需要在并行区域上声明为私有。就现在而言,我很惊讶任何事情都在发生,因为“m”不能是私人的。关键区域允许它为“i”循环工作,但是关键区域应该能够被减少——尽管我已经有一段时间没有做shell排序了。所以这里有很多问题
因此,首先,正如已经指出的,i和j(以及temp)需要保密;m和a需要共享。使用openmp的一个有用的方法是使用默认值(无),这样您就不得不仔细考虑在并行部分中使用的每个变量的作用,以及它需要是什么。那么这个
#pragma omp parallel for private (i,j,temp) shared(a,m) default(none)
这是一个好的开始。特别是将m私有化有点麻烦,因为这意味着m在并行区域内是未定义的。顺便说一下,循环应该以m=n/2开始,而不是m=2
此外,对于shell排序,您不需要关键区域,或者您不应该这样做。稍后我们将看到,问题并不是多个线程在同一个元素上工作。因此,如果你摆脱了这些东西,你最终会得到一些几乎有效但并不总是有效的东西。这就引出了更根本的问题
基本上,a的工作方式是,将数组分解成许多子数组(这里是m子数组),然后插入排序(对于小数组非常快),然后重新组装;然后继续将它们分成越来越少的子阵列并进行插入排序(非常快,因为它们是部分排序的)。对这些子阵列进行排序是可以并行完成的事情。(实际上,使用这种简单的方法,内存争用将是一个问题,但仍然存在)
现在,你得到的代码是串行的,但是如果你只是把j循环包装成一个omp并行的
,它就不能工作了。原因是通过j循环的每次迭代都会执行一个插入排序中的一个步骤。第j+m次循环迭代执行下一步。但是不能保证它们是由同一个线程完成的,或者是按顺序完成的!如果另一个线程在第一个线程进行第j次迭代之前已经进行了第j+m次迭代,那么插入排序将出错,排序将失败
因此,实现这一点的方法是重写shell排序,使并行性更加明确——不要将插入排序分解为一系列串行步骤
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
void insertionsort(int a[], int n, int stride) {
for (int j=stride; j<n; j+=stride) {
int key = a[j];
int i = j - stride;
while (i >= 0 && a[i] > key) {
a[i+stride] = a[i];
i-=stride;
}
a[i+stride] = key;
}
}
void shellsort(int a[], int n)
{
int i, m;
for(m = n/2; m > 0; m /= 2)
{
#pragma omp parallel for shared(a,m,n) private (i) default(none)
for(i = 0; i < m; i++)
insertionsort(&(a[i]), n-i, m);
}
}
void printlist(char *s, int a[], int n) {
printf("%s\n",s);
for (int i=0; i<n; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int checklist(int a[], int n) {
int result = 0;
for (int i=0; i<n; i++) {
if (a[i] != i) {
result++;
}
}
return result;
}
void seedprng() {
struct timeval t;
/* seed prng */
gettimeofday(&t, NULL);
srand((unsigned int)(1000000*(t.tv_sec)+t.tv_usec));
}
int main(int argc, char **argv) {
const int n=100;
int *data;
int missorted;
data = (int *)malloc(n*sizeof(int));
for (int i=0; i<n; i++)
data[i] = i;
seedprng();
/* shuffle */
for (int i=0; i<n; i++) {
int i1 = rand() % n;
int i2 = rand() % n;
int tmp = data[i1];
data[i1] = data[i2];
data[i2] = tmp;
}
printlist("Unsorted List:",data,n);
shellsort2(data,n);
printlist("Sorted List:",data,n);
missorted = checklist(data,n);
if (missorted != 0) printf("%d missorted nubmers\n",missorted);
return 0;
}
#包括
#包括
#包括
void insertionsort(int a[],int n,int步长){
对于(int j=stride;j=0&&a[i]>键){
a[i+步幅]=a[i];
i-=步幅;
}
a[i+步幅]=键;
}
}
无效外壳排序(int a[],int n)
{
int i,m;
对于(m=n/2;m>0;m/=2)
{
#pragma omp parallel for shared(a,m,n)private(i)default(无)
对于(i=0;i 对于(inti=0;i,这里有很多问题
首先,正如已经指出的,i和j(和temp)需要是私有的;m和a需要共享。openmp的一个有用的方法是使用默认值(无),这样您就不得不考虑在并行部分中使用的每个变量是什么,以及它需要是什么
#pragma omp parallel for private (i,j,temp) shared(a,m) default(none)
这是一个好的开始。特别是将m私有化是一个灾难,因为这意味着m在并行区域内是未定义的。顺便说一下,循环应该从m=n/2开始,而不是从m=2开始
此外,对于shell排序,您不需要关键区域——或者您不应该这样做。稍后我们将看到,问题并不是多个线程在同一个元素上工作。因此,如果您去掉这些东西,您最终会得到一些几乎可以工作,但并不总是有效的东西。这就引出了更基本的问题
基本上,a的工作方式是,将数组分解为许多子数组(这里是,m
),然后插入排序(对于小数组非常快),然后重新组装;然后继续将它们分解为越来越少的子数组并插入排序(非常快,因为它们是部分排序的)。对这些子数组进行排序是可以并行完成的。(实际上,使用这种简单的方法,内存争用将是一个问题,但仍然存在)
现在,你得到的代码是串行的,但是如果你只是用omp并行的方式将j循环包装成,它就不能工作了。原因是通过j循环的每次迭代都会执行插入排序中的一个步骤。第j+m次循环迭代会执行下一个步骤。但是没有保证