私があなたのコードを理解できる限り、データがコピーされない限りデータの処理を続行できないため、並行して実行する意味がありません。処理スレッドは、コピースレッドが終了して設定されるのを待ってCPU時間を無駄にします.国旗。次に、両方の操作を 1 つのブロックにマージしてみませんか。
#pragma omp parallel num_threads(8)
{
int tid = omp_get_thread_num();
copydata(arrayofPtrs[tid]);
processingdata(arrayofPtrs[tid]);
}
元のアイデアを保持したい場合、おそらくコピーと処理の両方が非同期で繰り返し行われる場合は、Open MPatomic
操作を使用してフラグへのアクセスを同期する必要があります。
#pragma omp parallel num_threads(16)
{
int tid = omp_get_thread_num();
if (tid < 8)
{
copydata(arrayofPtrs[tid]);
#pragma omp atomic write
flag[tid] = 1;//flag is an array of volatile int where its initial values are all 0.
}
else
{
for (int i = 0; i < 100000; ++i)
{
#pragma omp atomic read
int ready = flag[tid-8];
if (ready == 1)
{
processingdata(arrayofPtrs[tid-8]);
break;
}
else
Sleep(200);
}
}
}
ほとんどのコンパイラではatomic
、参照された変数が揮発性になるという副作用があります。次を使用してメモリ ビューを明示的に更新することもできますflush
。
#pragma omp atomic write
flag[tid] = 1;
#pragma omp flush(flag)
read
and句は、write
最近の OpenMP バージョンでのみサポートされています。これは、Win32 API を使用しているように見えます。そのため、OpenMP 2.0 のみを実装しているため修飾子をサポートしていない MSVC を使用している可能性がありますが、コードはコンパイルされ、意図したとおりに動作するはずですSleep()
。read
write
ビジー ループを回避するもう 1 つの方法は、OpenMP ロックを使用することです。ロックの配列を初期化し、コピー スレッドでそれらを取得し、各処理スレッドにロックの取得を待機させます。
omp_lock_t locks[8];
for (int i = 0; i < 8; i++)
omp_init_lock(&locks[i]);
#pragma omp parallel num_threads(16)
{
int tid = omp_get_thread_num();
// Have the first 8 threads acquire the locks
if (tid < 8)
omp_set_lock(&locks[tid]);
#pragma omp barrier
// Now locks are set and processing can continue
if (tid < 8)
{
copydata(arrayofPtrs[tid]);
omp_unset_lock(&locks[tid]);
}
else
{
omp_set_lock(&locks[tid-8]);
processingdata(arrayofPtrs[tid-8]);
omp_unset_lock(&locks[tid-8]);
}
}
for (int i = 0; i < 8; i++)
omp_destroy_lock(&locks[i]);
OpenMP ロックの代わりに POSIX セマフォの Win32 イベントを使用して同じことを実装することもできます。このアプローチの利点は、フラグが設定されるのを待っている間、明示的にループする必要がないことです。むしろ、omp_set_lock()
コピー中のスレッドがそのロックを解放するまで、呼び出しはブロックされます。Win32 イベントを使用WaitForSingleObject(hEvent, INFINITE);
すると、コピー スレッドがシグナルを送信するのを待つことができます。