2011-10-20 28 views
1

我的程序包含一个用于()循环处理一些原始图像数据,一行行,我想使用OpenMP这样的并行:为并行化的()循环提供线程专用预分配缓冲区?

... 
#if defined(_OPENMP) 
     int const threads = 8; 
     omp_set_num_threads(threads); 
     omp_set_dynamic(threads); 
#endif 
     int line = 0; 
#pragma omp parallel private(line) 
     { 
      // tell the compiler to parallelize the next for() loop using static 
      // scheduling (i.e. balance workload evenly among threads), 
      // while letting each thread process exactly one line in a single run 
#pragma omp for schedule(static, 1) 
      for(line = 0 ; line < max; ++line) { 
       // some processing-heavy code in need of a buffer 
      } 
     } // end of parallel section 
.... 

问题是这样的:

是使用标准OpenMP编译指示/函数(从而不需要为每个循环分配新的缓冲区),可以向执行我的循环的团队的每个线程提供单独的(预分配的)缓冲区(指针)?

在此先感谢。

比约恩·

回答

1

我可以理解你错了,但我认为这应该这样做:

#pragma omp parallel 
{ 
    unsigned char buffer[1024]; // private 

    // while letting each thread process exactly one line in a single run 
    #pragma omp for // ... etc 
    for(int line = 0; line < max; ++line) { 
      //... 
    } 
} 

如果你真的意味着你要共享不同的parallell块相同的缓冲区,你会必须求助于线程本地存储。 (Boost和C++ 11相比直接使用TlsAlloc和朋友有更容易做的工具(更易移植)。

注意,这种方法取代一些线程安全检查的负担回到了程序员,因为它是完全有可能有不同的omp parallel部分在同一时间运行,特别是当被嵌套它们。

考虑到并行块可能在运行时嵌套,即使它们不是在词汇上是嵌套。在实践中,这通常不是很好的风格 - 而且往往导致糟糕的表现。但是,这是你在做这件事时需要注意的事情)。

+0

这里的问题是必要的缓冲区可能对堆栈太大,特别是当我们使用多个线程时。在'omp parallel private'#pragma中添加'buffer'是否也适用于指针? – Bjoern

+0

IIRC'private'适用于/ names /(标识符)。无论如何,我怀疑你必须指定它。根据我的经验,声明_inside_并行部分的变量是每个线程的。所以是的,随便声明'std :: vector <...>缓冲区'或者新的。不要忘记删除它:) – sehe

+0

非常感谢!我会给这个镜头,明天的第一件事=)。 – Bjoern

2

threadprivatehttp://msdn.microsoft.com/en-us/library/2z1788dd

static int buffer[BUFSIZE]; 
#pragma omp threadprivate(buffer) 

此编译工作在一个全局/静态变量,所以你不必担心堆栈溢出。 (在这种堆栈溢出的情况下,通过调整链接器选项来增加堆栈大小并不是一个坏主意。)

请注意,对于threadprivate,编译器可能有不同的实现细节。例如,如果变量具有构造函数,VS 2010编译器不能使threadprivate。但是,英特尔C/C++编译器很大程度上完成了这项工作。

使用单独的omp parallelomp for也是一个好主意,因为sehe显示它。但是,使用threadprivate可以直接使用omp parallel for。如果你需要分配你自己的线程本地存储,在许多情况下,你实际上并不需要调用诸如TlsAlloc的操作系统特定的函数调用。您可以简单地分配一个包含N个数据结构的数组。然后,通过使用omp_get_thread_num来访问它们,它提供了从0到N-1的线程ID。当然,您必须考虑通过插入填充来确保每个数据结构应与不同的高速缓存行(主要是现代CPU高速缓存具有64字节高速缓存行)对齐,从而实现虚假共享。

+0

对于omp_get_thread_num方法为+1。这个解决方案更符合我原先的想法。看起来我们正在这里汇总一个体面的问题=)... – Bjoern