我遇到了问题,代码并行部分内的内存分配过多导致异常。在许多情况下,我通过将内存分配从循环中拉出来完全解决这个问题,以便内存变得可重用,并且仅在需要增长时才再次分配。如果仅在相对较短且简单的并行循环内使用存储器,则这可能很简单。例如,假设以下伪代码是我的原始循环:
omp parallel for
for 1000 times {
mem = alloc
do stuff in mem and get result
free mem
}
然后为了使 mem
可重用,我可以这样写:
omp parallel {
mem = alloc
omp for
for 1000 times {
if mem too small then grow mem
do stuff in mem and get result
}
free mem
}
这当然假设我的线程少于 1000 个,否则没有什么区别。
随着更复杂的循环,可读性开始受到影响,特别是因为无法突破并行部分。例如,如果我想在内存分配失败时中止,则后续的代码块必须位于
if(not failed) {
do some stuff
}
而不是更好的
if(failed) return
do some stuff
如果一个函数有很多并行区域,中间有串行区域,并且您希望在这些并行区域中重用内存,情况会变得更糟。此时,您实际上是在使整个函数并行,然后显式标记串行部分。
我想到 OpenMP 的 threadprivate
子句可以避免很多麻烦。它允许您创建全局变量的私有(private)副本。然后,为整个程序创建可重用的内存块就变得非常容易,更不用说单个函数了。如果您认为全局变量是良好的风格,那么这似乎是理所当然的。
我是否误解了某些东西,或者使我想要重用全局的所有内容都会比将变量保留在函数内要少得多?如果是这样,是否没有相当于 threadprivate
的“功能级别”?
(我应该提到,我使用的是 Visual Studio 2012,它被 OpenMP 2.0 困住了,显然无法执行诸如更改 OpenMP 专用线程堆栈大小之类的操作。我需要留在 Windows 中,因此如果出现以下情况,我可能会切换到英特尔的编译器:新版本的 OpenMP 可以为我提供很大帮助。)
最佳答案
threadprivate
是 __thread
变量属性的 OpenMP 版本,如果使用正确的编译器选项,它们甚至是兼容的。它驻留在线程本地存储中。您可以将指针放入线程本地存储中,但必须确保在线程退出时释放该内存,这对于 OpenMP 来说很困难。
如果您必须分配大量内存(大于堆栈大小),那么我担心您正在做的事情是最好的。否则,请考虑将内存放在堆栈上,保证在线程退出时释放内存。
此外,最好的做法是使驻留在并行区域中的代码尽可能小,并将所有内容移至单独的函数中(这正是 OpenMP 在幕后为您所做的事情)。
您可能需要一个好的多线程内存分配器。我读过关于 Hoard 的好东西,但从未尝试过。
关于c - OpenMP 和私有(private)可重用内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21942303/