編集:プリプロセッサを使用してこれを行う方法を考えました。これにより、重複コードの問題が修正されますが、コンパイルとリンクが少し複雑になります。コンパイラで OpenMP が有効になっていない場合、OpenMP コンストラクトが無視されるという機能を使用します。
#include <stdlib.h>
void setQueen(int* x, int y, int z) {
/*code*/
}
#if defined _OPENMP
void solve_parallel(const int size)
#else
void solve_serial(const int size)
#endif
{
int i;
#pragma omp parallel for
for(i = 0; i < size; i++) {
int *queens = (int*)malloc(sizeof(int)*size);
setQueen(queens, 0, i);
free(queens);
}
}
でコンパイル
gcc -O3 -c foo.c -o solve_serial
gcc -O3 -fopenmp -c foo.c solve_parallel
次に、関数ポインターを使用して以下のようなメイン関数を使用し、solve_serial および solve_parallel オブジェクト ファイルにリンクできます。
別のオプションは、次のようにスレッド数を渡すことです。
void solve(const int nthreads)
{
int i;
const int size = 10;
#pragma omp parallel for num_threads(nthreads)
for(i = 0; i < size; i++) {
int *queens = (int*)malloc(sizeof(int)*size);
setQueen(queens, 0, i);
free(queens);
}
}
ただし、nthreads=1 の場合でも、コンパイラは OpenMP コンストラクトを挿入する必要があります。これにより、OpenMP でコンパイルしない場合と比較してパフォーマンスが低下する可能性があり、したがって偏った比較が行われる可能性があります。
より公平な解決策は、OpenMP を使用する場合と使用しない場合で 2 つの関数を定義し、関数ポインターの配列を使用することです (以下を参照)。これは、最適化のために比較したい関数のバリエーションがいくつかある場合に便利です。
#include <stdlib.h>
#include <omp.h>
void solve_parallel(const int size)
{
int i;
#pragma omp parallel for
for(i = 0; i < size; i++) {
int *queens = (int*)malloc(sizeof(int)*size);
setQueen(queens, 0, i);
free(queens);
}
}
void solve_serial(const int size)
{
int i;
for(i = 0; i < size; i++) {
int *queens = (int*)malloc(sizeof(int)*size);
setQueen(queens, 0, i);
free(queens);
}
}
int main(void) {
const int size = 100;
int i;
double dtime[2];
void (*solve[2])(int);
solve[0] = solve_serial;
solve[1] = solve_parallel;
solve[1](size); /* run OpenMP once to warm it up */
for(i=0; i<2; i++) {
dtime[i] = omp_get_wtime();
solve[i](size);
dtime[i] = omp_get_wtime() - dtime[i];
}
return 0;
}