C++中的内存分配和赋值与openMP

4
我正在使用openMP优化一个for循环。在每个线程中,将会临时使用一个大数组(当该线程完成时不再需要)。由于我不想重复分配和删除这些数组,所以我计划分配一个大的内存块,并将其分配给每个线程的一部分。为了避免冲突,我应该为每个运行线程分配一个唯一的ID,该ID不应更改并且不能等于另一个线程。因此,我的问题是,我可以使用函数omp_get_thread_num()返回的线程ID来实现这个目的吗?或者是否有任何高效的解决方案来完成这样的内存分配和分配任务?非常感谢!

3
可以。omp_get_thread_num()返回一个唯一的线程ID,它不会改变。使用线程ID来分割矩阵/数组是常见的做法。 - Aleksander Fular
你需要在同一并行区域或连续的并行区域之间保持内存持久吗?前者的一个例子是具有并行内部循环的串行外部循环。此外,omp_get_thread_num() 返回相同的线程 ID 并不一定意味着代码正在由同一进程线程执行。 - Hristo Iliev
谢谢,我不需要它持久化。我只需要确保每个内存块不会同时被不同的线程使用,所以第一个解决方案对我来说已经足够了。 - Chai ML
2个回答

5

您可以开始并行部分,然后开始分配变量/内存。在并行部分内声明的所有内容都是线程私有的,存在自己的堆栈中。例如:

#pragma omp parallel
{
    // every variable declared here is thread private
    int * temp_array_pointer = calloc(sizeof(int), num_elements);
    int temp_array_on_stack[num_elements];

    #pragma omp for
    for (...) {
         // whatever my loop does
    }

    // if you used dynamic allocation
    free(temp_array_pointer);
}

你认为在这里应该如何处理错误?任何一个calloc调用都可能失败。在我看来,更简单的方法是在程序启动时分配临时结构,这样你可以更轻松地处理错误。 - pburka
2
如果您使用自动变量(堆栈分配),则不需要错误处理。如果在并行部分中使用*alloc,那么是的,您应该在此处进行错误处理。我建议在并行部分内分配所有线程私有的内容,以避免传递指针时出现任何潜在的错误,并且如果您正在使用NUMA机器,则这将允许您将内存硬件本地化到执行线程,从而提高性能。 - Sergey L.
如果使用大的自动变量,则应该熟悉 ulimit -s(Un*x)/ /STACK:nnn(Windows)和 OMP_STACKSIZE - Hristo Iliev

0

一旦您的程序遇到并行区域,也就是一旦它触发了

#pragma omp parallel

线程(可能已在程序初始化时启动,也可能直到第一个并行构造才启动)将变为活动状态。在并行区域内,分配内存的任何线程(例如,分配给数组)都将在其自己的私有地址空间中分配该内存。除非线程释放内存,否则它将保留整个并行区域的内存。

如果您的程序首先在串行模式下为数组分配内存,然后在进入并行区域时将该数组复制到所有线程中,请使用firstprivate子句,并让运行时处理将数组复制到每个线程的私有地址空间中。

考虑到这一切,我不明白在遇到并行区域之前,为什么要分配大量内存,然后使用基于线程ID的计算来分割内存,以便在线程之间共享。


谢谢。我的目的是避免在线程中分配内存的开销。假设线程大小为8,每个线程将需要内存大小N,因此我只需要分配N*8内存,并让每个线程在其中拥有其自己的大小为N的私有部分。是的,我可以使用firstprivate子句复制数组指针,但这无法知道当前线程未使用的部分。 - Chai ML
1
啊,所以你宁愿让一个线程分配8n字节而不是让8个线程分别分配n字节。我不确定这是否只是一种不必要的优化 - 要说服我这不是这样,你需要向我展示数据。至于指针,是你把它们带入了讨论,而不是我。 - High Performance Mark
实际上,我想在一开始就分配8n而不是每个线程分配n,总的线程大小远远超过8,但是最多只有8个线程同时运行。 - Chai ML

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接