我遇到的问题是,我的代码的并行部分中的内存分配过多会导致异常。在许多情况下,我通过从循环中提取内存分配来完全解决这个问题,这样内存就可以重用,只有在需要增长时再次分配。如果仅在相对短且简单的并行循环中使用存储器,则这可以是简单的。例如,假设以下伪代码是我的原始循环:
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
条款可以省去很多麻烦。它允许您创建全局变量的私有副本。然后,为整个程序创建可重用的内存块变得非常容易,更不用说单个函数了。如果你认为全局变量是好的风格,那么它似乎是一个明智的选择。
我是否误解了某些内容,或者是否正在使我想要重用全局的内容比将变量保留在函数中要少得多?如果是这样,是否没有“{level 1”}等效的“功能级别”?
(我应该提到我在使用OpenMP 2.0的Visual Studio 2012中,显然无法做更改OpenMP私有线程堆栈大小的事情。我需要留在Windows中,以便我可以切换到Intel的编译器,如果较新版本的OpenMP可以帮助我。)
答案 0 :(得分:0)
threadprivate
是__thread
变量属性的OpenMP版本,具有正确的编译器选项,甚至可以兼容。它驻留在线程本地存储中。您可以将指针放入线程本地存储中,但是当线程退出时,您必须确保释放该内存,这对于OpenMP来说是困难的。
如果你必须分配大量内存(超过你的堆栈大小),那么我担心你所做的事情是最好的。否则,请考虑将内存放在堆栈上,保证在线程退出时释放。
同样优良的做法是尽可能减少驻留在并行区域中的代码,并将所有内容移动到单独的函数中(无论如何,这都是OpenMP为您做的)。
你可能需要一个好的多线程内存分配器。我已经阅读了关于Hoard的好东西,但从未尝试过。