2016-08-10 4 views
2

Cでリアルタイム信号処理アルゴリズムを実装していますが、マルチスレッドを使用してコードの一部を並列化しようとしています。マルチスレッドの結果がCで遅くなる

シングルスレッド実装するためのコードは、マルチスレッド実装では、私はいくつかのスレッドを作成し、特定のデータアレイで処理するためにそれらをシグナリング保つ糸スプールのアイデアを使用し

void calcTheta(float *theta, float **s, float ***q, float ***g, 
       int *Ki, int m, int numObv, int numTask) { 
    int i, j, k; 

    for (i = 0; i < m; i++) { 
     theta[i] = 0; 
     for (j = 0; j < numObv; j++) { 
      for (k = 0; k < numTask; k++) { 
       theta[i] += (Ki[k] * (pow(fabs(q[i][j][k]), 2)/g[i][j][k]) - s[i][k])/
          (s[i][k] * (s[i][k] - (pow(fabs(q[i][j][k]), 2)/g[i][j][k]))); 
      }//k 
     }//j 
     theta[i] = (numTask * numObv)/theta[i]; 
    }//i 
} 

あります。コードは以下である:

#define NUM_THREADS_THETA 2 
#define TRUE 1 
#define FALSE 0 
#define READY 1 
#define DONE 0 

struct threadThetaData { 
    float *theta; 
    float **s; 
    float ***q; 
    float ***g; 
    int *Ki; 
    int numObv; 
    int numTask; 
    int threadId; 
}; 

struct threadThetaData dataArrayTheta[NUM_THREADS_THETA]; 
int termThread[NUM_THREADS_THETA]; 
int statusThread[NUM_THREADS_THETA]; 
int iVal[NUM_THREADS_THETA]; 
pthread_mutex_t mutexThreadProc[NUM_THREADS_THETA]; 
pthread_mutex_t mutexMainProc[NUM_THREADS_THETA]; 
pthread_cond_t condThreadProc[NUM_THREADS_THETA]; 
pthread_cond_t condMainProc[NUM_THREADS_THETA]; 

void *doProcTheta(void *threadArg) { 
    struct threadThetaData *myData = (struct threadThetaData *)threadArg; 

    float *theta = myData->theta; 
    float **s = myData->s; 
    float ***q = myData->q; 
    float ***g = myData->g; 
    int *Ki = myData->Ki; 
    int numObv = myData->numObv; 
    int numTask = myData->numTask; 
    int threadId = myData->threadId; 

    int j, k; 

    while(1) { 
     //printf("thread %d waiting for signal from master..\n", threadId); 
     pthread_mutex_lock(&mutexThreadProc[threadId]); 
     while (statusThread[threadId] != READY) 
      pthread_cond_wait(&condThreadProc[threadId], &mutexThreadProc[threadId]); 
     pthread_mutex_unlock(&mutexThreadProc[threadId]); 

     //printf("thread %d got signal from master..\n", threadId); 

     if (termThread[threadId] == TRUE) 
      pthread_exit(NULL); 

     theta[iVal[threadId]] = 0; 
     for (j = 0; j < numObv; j++) { 
      for (k = 0; k < numTask; k++) { 
       theta[iVal[threadId]] += (Ki[k]*(pow(fabs(q[iVal[threadId]][j][k]),2)/g[iVal[threadId]][j][k]) - s[iVal[threadId]][k])/(s[iVal[threadId]][k]*(s[iVal[threadId]][k] - (pow(fabs(q[iVal[threadId]][j][k]),2)/g[iVal[threadId]][j][k]))); 
      }//k 
     }//j 
     theta[iVal[threadId]] = (numTask*numObv)/theta[iVal[threadId]]; 

     pthread_mutex_lock(&mutexMainProc[threadId]); 
     statusThread[threadId] = DONE; 
     pthread_cond_signal(&condMainProc[threadId]); 
     pthread_mutex_unlock(&mutexMainProc[threadId]); 

     //printf("thread %d signaled to master..\n", threadId); 
    } 
} 

void calcTheta(float *theta,float **s,float ***q,float ***g,int *Ki,int m, int numObv, int numTask) 
{ 
    int i,j; 

    pthread_t thetaThreads[NUM_THREADS_THETA]; 
    int numThreadBlks = m/NUM_THREADS_THETA; 
    int numThreadRem = m%NUM_THREADS_THETA; 
    int mCount = 0; 

    for(i=0;i<NUM_THREADS_THETA;i++) 
    { 
     pthread_mutex_init(&mutexThreadProc[i], NULL); 
     pthread_mutex_init(&mutexMainProc[i], NULL); 
     pthread_cond_init (&condThreadProc[i], NULL); 
     pthread_cond_init (&condMainProc[i], NULL); 
     dataArrayTheta[i].theta = theta; 
     dataArrayTheta[i].s = s; 
     dataArrayTheta[i].q = q; 
     dataArrayTheta[i].g = g; 
     dataArrayTheta[i].Ki = Ki; 
     dataArrayTheta[i].numObv = numObv; 
     dataArrayTheta[i].numTask = numTask; 
     dataArrayTheta[i].threadId = i; 
     termThread[i] = FALSE; 
     statusThread[i] = DONE; 
     pthread_create(&thetaThreads[i],NULL,doProcTheta,(void *)&dataArrayTheta[i]); 

    } 

    for(i=0;i<numThreadBlks;i++) 
    { 
     for(j=0;j<NUM_THREADS_THETA;j++) 
     { 
      pthread_mutex_lock(&mutexThreadProc[j]); 
      statusThread[j] = READY; 
      iVal[j] = mCount; 
      mCount++; 
      pthread_cond_signal(&condThreadProc[j]); 
      pthread_mutex_unlock(&mutexThreadProc[j]); 
      //printf("Signaled thread %d from master ... Waiting on signal ..\n",j); 
     } 

     for(j=0;j<NUM_THREADS_THETA;j++) 
     { 
      pthread_mutex_lock(&mutexMainProc[j]); 
      while (statusThread[j] != DONE) 
       pthread_cond_wait(&condMainProc[j], &mutexMainProc[j]); 
      pthread_mutex_unlock(&mutexMainProc[j]); 
      //printf("Got signal from thread %d to master \n",j); 
     } 

    } 

    for(j=0;j<numThreadRem;j++) 
    { 
     pthread_mutex_lock(&mutexThreadProc[j]); 
     statusThread[j] = READY; 
     iVal[j] = mCount; 
     mCount++; 
     pthread_cond_signal(&condThreadProc[j]); 
     pthread_mutex_unlock(&mutexThreadProc[j]); 
    } 

    for(j=0;j<numThreadRem;j++) 
    { 
     pthread_mutex_lock(&mutexMainProc[j]); 
     while (statusThread[j] != DONE) 
      pthread_cond_wait(&condMainProc[j], &mutexMainProc[j]); 
     pthread_mutex_unlock(&mutexMainProc[j]); 
    } 

    for(j=0;j<NUM_THREADS_THETA;j++) 
    { 
     pthread_mutex_lock(&mutexThreadProc[j]); 
     statusThread[j] = READY; 
     termThread[j] = TRUE; 
     pthread_cond_signal(&condThreadProc[j]); 
     pthread_mutex_unlock(&mutexThreadProc[j]); 

     pthread_join(thetaThreads[j],NULL); 

     pthread_mutex_destroy(&mutexThreadProc[j]); 
     pthread_cond_destroy(&condThreadProc[j]); 
     pthread_mutex_destroy(&mutexMainProc[j]); 
     pthread_cond_destroy(&condMainProc[j]); 
    } 

} 

アレイ寸法:

m=661 
numObv=96 
numTask=1024 

ランタイムであり、特定のデータセットについて

float theta[m]; 
float s[m][numTask]; 
float q[m][numObv][numTask]; 
float g[m][numObv][numTask]; 
int Ki[numTask]; 

Single threaded : 4.5 seconds 
Multithreaded with 2 threads : 6.9 seconds 

私はランタイムを予想しましたマルチスレッド化されたコード他の方法では、シングルスレッドコードよりもパフォーマンスが向上します。私がここで欠けているものへの指針は、非常に高く評価されるだろう。

+5

ロック間の作業が不十分であるため、ロックを処理するのに費やされる時間は、保存された作業時間よりも長くなります。 – chqrlie

+0

私はdoProcTheta関数のthetaの計算をロックの内側に移動できます。 – anshu

+0

あなたの質問に大いに関係しているだけです。まだわからない場合は、OpenMPを見てください。 – Phillip

答えて

5

あなたのマルチスレッド実装は、手元の問題の複雑さを増しているようです。単一のスレッドコードは、各theta要素が他のすべての要素と独立して計算されることを示しています。

したがって、スレッド間のデータ交換/同期の必要がないため、mutexと条件文は必要ありません。スレッドがtheta計算の異なる範囲を扱うようにしてください。

m=661と2つのスレッドの場合、最初のスレッドはthetaを範囲0..330で計算し、2番目のスレッドはthetaを範囲331..660で計算する必要があります。 2つのスレッドを起動し、それらが完了するのを待ちます(別名結合)。

マルチスレッド実装では、ほぼ単一のスレッドコードを使用できます。必要なのは、関数に開始インデックスを追加することだけです。

+0

+1あなたが書いたことは別として、私は処理関数の中で 'while(1) 'の必要性を理解していません。 mutexの使い方はまったく必要ありません。 – Groo

関連する問題