2

編集:同じプログラムを問題なく同時に 2 回実行できます。これを 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();
   }
}

まだ運がありません。

4

3 に答える 3

5

MemAllocFunctionInDLL、FunctionDefinedInDLL、MemDeallocFunctionInDLL がスレッドセーフまたは再入可能であることを確認してください。つまり、これらの関数は静的変数または共有変数ですか? このような場合、これらの変数が他のスレッドによって破損されていないことを確認する必要があります。

omp-for がなくても問題ないという事実は、いくつかの関数をスレッドセーフにするために正しく記述していないことを意味する可能性があります。

Mem(Alloc|Dealloc)FunctionInDLL でどのようなメモリ割り当て/解放関数が使用されているかを確認したいと思います。

追加: DLL 内の関数がスレッド セーフではないことは確かです。このプログラムは問題なく同時に実行できます。はい、非常にまれですが、プログラムがシステム全体の共有リソース (グローバル メモリやプロセス間の共有メモリなど) を使用しない限り問題ありません。この場合、スレッド内に共有変数がないため、プログラムは正常に動作します。

ただし、これらの関数をマルチスレッドで (つまり、単一のプロセスで) 呼び出すと、プログラムがクラッシュします。これは、スレッド間にいくつかの共有変数があり、破損している可能性があることを意味します。

これは 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][..]

はい、とても簡単です。ただし、この種のコードには、誤った共有の問題がある可能性があります。ただし、偽の共有はパフォーマンスの問題であり、正確さではありません。

まず、静的変数とグローバル変数をプライベート化してみてください。次に、それが正しいかどうかを確認します。次に、得られるスピードアップを確認します。スピードアップがスケーラブルであれば (クアッド コアで 3.7 倍速くなるなど)、問題ありません。ただし、スピードアップが遅い場合 (クアッド コアで 2 倍のスピードアップなど) は、おそらく偽の共有の問題を調べます。偽共有の問題を解決するには、データ構造にパディングを入れるだけです。

于 2009-11-05T18:12:58.680 に答える
2

それ以外の

delete Data

あなたは書く必要があります

delete [] Data;

new [] を行う場合は、必ず delete [] を使用してください。

あなたの問題はopenmpに固有のものではないようです。#pragma parallel を含めずにアプリケーションを実行しようとしましたか?

于 2009-11-05T17:00:29.607 に答える
2

default(shared) は、すべての変数がスレッド間で共有されることを意味しますが、これは望ましくありません。それをデフォルト(なし)に変更します。

Private(X) はスレッドごとに X のコピーを作成しますが、いずれも初期化されないため、構築が必ずしも実行されるとは限りません。

最初のアプローチの方が良いと思います。Dealloc 呼び出しにブレークポイントを設定し、メモリ ポインタとその内容を確認してください。単一の呼び出しの最後またはスレッドの後にメモリが上書きされたかどうかを確認するために、ガード バイトを確認できます。

ちなみに、ompループなしで一度実行すればうまくいくと思いますか?

于 2009-11-05T17:07:58.430 に答える