OpenMP:堆腐败的原因,任何人?

时间:2009-11-05 16:42:54

标签: c++ c dll openmp visual-c++-2005

编辑:我可以同时运行相同的程序两次,同时没有任何问题 - 如何使用OpenMP或其他方法复制它?

这是问题的基本框架。

//Defined elsewhere
class SomeClass
{
public:
  void Function()
  {
    // Allocate some memory
    float *Data;
    Data = new float[1024];

    // Declare a struct which will be used by functions defined in the DLL
    SomeStruct Obj;
    Obj = MemAllocFunctionInDLL(Obj);

    // Call it
    FunctionDefinedInDLL(Data,Obj);

    // Clean up
    MemDeallocFunctionInDLL(Obj);
    delete [] Data;        
  }
}

void Bar()
{
   #pragma omp parallel for
   for(int j = 0;j<10;++j)
   {
     SomeClass X;
     X.Function();
   }
}

我已经验证,当尝试通过MemDeallocFunctionInDLL()释放某些内存时,_CrtIsValidHeapPointer()断言失败。

这是因为两个线程都在写入同一个内存吗?

所以为了解决这个问题,我想我会SomeClass私有(这对我来说完全不同,所以任何帮助都会受到赞赏)。

void Bar()
{
   SomeClass X;
   #pragma omp parallel for default(shared) private(X)
   for(int j = 0;j<10;++j)
   {         
     X.Function();
   }
}

现在它在Data开头尝试分配内存时失败。

注意:如果需要,我可以对DLL进行更改

注意:在没有#pragma omp parallel for

的情况下运行良好

编辑:现在Bar如下所示:

void Bar()
{
   int j
   #pragma omp parallel for default(none) private(j)
   for(j = 0;j<10;++j)
   {
     SomeClass X;         
     X.Function();
   }
}

仍然没有运气。

3 个答案:

答案 0 :(得分:5)

签出MemAllocFunctionInDLL,FunctionDefinedInDLL,MemDeallocFunctionInDLL 线程安全重入。换句话说,这些函数是做静态变量还是共享变量?在这种情况下,您需要确保这些变量不会被其他线程破坏。

没有omp-for的事实很好可能意味着你没有正确地编写一些函数来保证线程安全。

我想看看Mem(Alloc | Dealloc)FunctionInDLL中使用了哪种内存分配/自由函数。

已添加:我非常确定您在DLL中的函数不是线程安全的。您可以同时运行此程序而不会出现问题。是的,它应该没问题,除非你的程序使用系统范围的共享资源(例如全局内存或进程间的共享内存),这是非常罕见的。在这种情况下,线程中没有共享变量,因此您的程序运行正常。

但是,在 mutithreads 中调用这些函数(这意味着在单个进程中)会导致程序崩溃。这意味着线程之间存在一些共享变量,并且它可能已被破坏。

这不是OpenMP的问题,而只是一个多线程错误。解决这个问题可能很简单。请查看DLL函数是否可以安全地被许多线程并发调用。

如何私有化静态变量

假设我们有这样的全局变量:

static int  g_data;
static int* g_vector = new int[100];

私有化只不过是为每个线程创建私有副本。

int  g_data[num_threads];
int* g_vector[num_threads];
for (int i = 0; i < num_threads; ++i)
  g_vector[i] = new int[100];

然后,对这些变量的任何引用都是

// Thread: tid
g_data[tid] = ...
.. = g_vector[tid][..]

是的,这很简单。但是,此类代码可能存在false sharing问题。但是,虚假共享是表现的问题,而不是正确性。

首先,尝试私有化任何静态和全局变量。然后,检查它的正确性。接下来,看看你会得到的加速。如果加速是可扩展的(比如在四核上快3.7倍),那么它没关系。但是,在低速加速的情况下(例如四核上加速2倍),您可能会看到错误的共享问题。要解决错误共享问题,您只需在数据结构中添加一些填充。

答案 1 :(得分:2)

而不是

delete Data

你必须写

delete [] Data;

无论您在哪里执行新[],请务必使用delete []。

看起来你的问题并不是针对openmp的。您是否尝试在不包含#pragma parallel的情况下运行应用程序?

答案 2 :(得分:2)

default(shared)表示所有变量在线程之间共享,这不是您想要的。将其更改为默认值(无)。

Private(X)将为每个线程制作一个X的副本,但是,它们都不会被初始化,因此不一定会执行任何构造。

我认为你的初始方法会更好,在Dealloc调用中放置一个断点,看看内存指针是什么以及它包含什么。您可以看到guard bytes来判断在单个调用结束时或线程之后是否覆盖了内存。

顺便说一下,如果你运行一次没有omp循环,我假设这个有效吗?