2011-01-05 105 views
0

我有一个for循环,使用(有点复杂)的计数器对象sp_ct来初始化一个数组。串行代码看起来像优雅地初始化循环openmp线程

sp_ct.depos(0); 
for(int p=0;p<size; p++, sp_ct.increment()) { 
    in[p]=sp_ct.parable_at_basis(); 
} 

我的计数器支持并行化,因为它可以后p增量初始化状态,导致下面的工作代码片段:

int firstloop=-1; 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p=0;p<size;p++) { 
    if(firstloop == -1) { 
     sp_ct.depos(p); firstloop=0; 
    } else { 
     sp_ct.increment(); 
    } 
    in[p]=sp_ct.parable_at_basis(); 
    } // end omp paralell for 

我不喜欢因为这混乱,它掩盖了真正发生的事情,并且因为它在循环中有一个不必要的分支(是的,我知道这对于运行时间可能没有可测量的影响,因为它是,所以可预测......)。

我宁愿写类似

#pragma omp parallel for default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p=0;p<size;p++) { 
#prgma omp initialize // or something 
    { sp_ct.depos(p); } 
    in[p]=sp_ct.parable_at_basis(); 
    sp_ct.increment(); 
    } 
    } // end omp paralell for 

这可能吗?

+0

有没有理由不能在循环之外进行初始化? – 2011-01-05 23:56:36

+1

是的,初始化取决于分配给该线程的第一个“p”值。这在循环之外是未知的。 – 2011-01-06 00:05:38

回答

0

我明白你想要做什么,我不认为这是可能的。我只是想写一些我相信会达到同样目的的代码,并且有点干净,如果你喜欢它,那么甜美!

sp_ct.depos(0); 
in[0]=sp_ct.parable_at_basis(); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct,firstloop) 
    for(int p = 1; p < size; p++) { 
    sp_ct.increment(); 
    in[p]=sp_ct.parable_at_basis(); 
    } // end omp paralell for 
+0

您必须编辑#pragma语句,我确定。 (我真的不知道openmp,对不起) – 2011-01-06 00:30:32

+0

是的,这正是我的问题:你可以在'#pragma'中以某种方式进行初始化吗? – 2011-01-06 00:31:58

+0

我不知道,对不起,我无法回答你的问题。我可以问你为什么需要这样做? – 2011-01-06 00:47:27

1

如果我推广你的问题,问题是“如何执行平行部分的每个线程的初始化代码?”,是吗?您可以使用firstprivate子句的属性:“给定变量的初始化或构造发生,就像在线程执行构造之前每个线程完成一次一样”。

struct thread_initializer 
{ 
    explicit thread_initializer(
    int size /*initialization params*/) : size_(size) {} 

    //Copy constructor that does the init 
    thread_initializer(thread_initializer& _it) : size_(_it.size) 
    { 
    //Here goes once per thread initialization 
    for(int p=0;p<size;p++) 
     sp_ct.depos(p); 
    } 

    int size_; 
    scp_type sp_ct; 
}; 

然后循环可以写成:

thread_initializer init(size); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(init) 
for(int p=0;p<size;p++) { 
    init.sp_ct.increment(); 
} 
in[p]=init.sp_ct.parable_at_basis(); 

不好的东西,你必须写这个额外的初始化和一些代码被移离其实际执行点之遥。好处是您可以重复使用它以及更简洁的循环语法。

0

Riko,执行sp_ct.depos(),因此只会根据需要调用.increment()以使计数器达到传递的参数。然后你可以使用此代码:

sp_ct.depos(0); 
#pragma omp parallel for \ 
     default(none) shared(size,in) firstprivate(sp_ct) 
for(int p=0;p<size;p++) { 
    sp_ct.depos(p); 
    in[p]=sp_ct.parable_at_basis(); 
} // end omp paralell for 

这个方案有一个额外的好处:你的实现只有当每个线程只接收一个块出0 - size工作。指定schedule(static)省略块大小时(OpenMP 4.0 Specification,章节2.7.1,第57页),情况如此。但由于您未指定schedule,所用的时间表将取决于实施(OpenMP 4.0 Specification,章节2.3.2)。如果实现选择使用dynamicguided,则线程将收到多个块,它们之间有间隙。所以一个线程可能会收到数据块0-20,然后数据块70-90,这会使第二个数据块上的psp_ct不同步。上述解决方案与所有时间表兼容。

1

从我可以告诉你可以做到这一点,通过手动定义块。这看起来有点像的东西,我想用感应做OpenMP中Induction with OpenMP: getting range values for a parallized for loop in OpenMP

所以,你可能想是这样的:

#pragma omp parallel 
{ 
    const int nthreads = omp_get_num_threads(); 
    const int ithread = omp_get_thread_num(); 
    const int start = ithread*size/nthreads; 
    const int finish = (ithread+1)*size/nthreads;  
    Counter_class_name sp_ct; 

    sp_ct.depos(start); 
    for(int p=start; p<finish; p++, sp_ct.increment()) { 
     in[p]=sp_ct.parable_at_basis(); 
    } 
} 

注意,除了一些声明和改变范围值这个代码几乎是相同的到串行代码。

此外,您不必声明任何共享或私有。在并行块内声明的所有内容都是私有的,并且外部声明的内容都是共享的你也不需要firstprivate。这使得代码更清晰和更清晰(恕我直言)。