将线程私有预分配缓冲区提供给并行化的for()循环?

时间:2011-10-20 14:40:16

标签: c++ visual-studio-2008 openmp

我的程序包含一个for()循环,它逐行处理一些原始图像数据,我想用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 pragma / function 为执行我的循环的团队的每个线程提供一个单独的(预分配的)缓冲区(指针)(从而无需分配新的缓冲区每个循环)?

提前致谢。

比约恩

2 个答案:

答案 0 :(得分:2)

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

#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部分同时运行,特别是当它们运行时正在嵌套。

考虑到并行块可以在运行时嵌套,即使它们不是词法嵌套的。在实践中,这通常不是好的风格 - 并且经常导致糟糕的表现。但是,在执行此操作时,您需要注意这一点。)

答案 1 :(得分:2)

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

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

此pragma适用于全局/静态变量,因此您无需担心堆栈溢出。 (在这种堆栈溢出的情况下,通过调整链接器选项来增加堆栈大小并不是一个坏主意。)

请注意,编译器可能具有threadprivate的不同实现细节。例如,如果变量具有构造函数,则VS 2010编译器无法进行threadprivate。但是,英特尔C / C ++编译器非常有效。

使用单独的omp parallelomp for也是个好主意,因为它显示了它。但是,使用threadprivate可以直接使用omp parallel for

仅供参考:即使您需要分配自己的线程本地存储,在许多情况下,您实际上并不需要调用特定于操作系统的函数调用,例如TlsAlloc。您可以简单地分配N个数据结构的数组。然后,使用omp_get_thread_num访问它们,该{{1}}提供从0到N-1的线程ID。当然,您必须通过插入填充来考虑错误共享,以确保每个数据结构应与不同的缓存行对齐(主要是现代CPU缓存具有64字节缓存行)。