2016-08-10 1 views
2

Ich implementiere einen Echtzeit-Signalverarbeitungsalgorithmus in C und ich versuche, einen Teil des Codes mit Multithreading zu parallelisieren.Multithread führt zu einer langsameren Leistung in C

Der Code für die Single-Threaded-Implementierung ist

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 
} 

Die multithreaded Implementierung verwendet Idee, einen Thread-Spooling wo ich einige Threads erzeugen und halten sie mit spezifischen Signalisierungsdatenfelder zu verarbeiten. Der Code ist unten:

#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]); 
    } 

} 

Array Dimensionen:

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

Für eine bestimmte Datenmenge in dem

m=661 
numObv=96 
numTask=1024 

die Laufzeiten sind:

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

ich erwartet, dass die Laufzeiten für der Multithread-Code zu gib mir etwas Performance-Verbesserung gegenüber dem Single-Thread-Code, wenn es umgekehrt ist. Irgendwelche Hinweise darauf, was ich hier vermisse, wären sehr willkommen.

+5

Nicht genügend Arbeit zwischen den Sperren führt zu mehr Zeit, die mit Sperren verbracht wird, als mit zeitsparender Parallelverarbeitung. – chqrlie

+0

Ich kann die Berechnung von Theta in der DoProcTheta-Funktion in das Schloss verschieben, würde das helfen ?? – anshu

+0

Nur lose auf Ihre Frage bezogen: Wenn Sie es noch nicht wissen, schauen Sie sich OpenMP an. – Phillip

Antwort

5

Ihre Multi-Thread-Implementierung scheint für das vorliegende Problem viel zu komplex zu sein. Der einzelne Thread-Code zeigt, dass jedes theta Element unabhängig von allen anderen theta Elementen berechnet wird.

Sie brauchen also keine Mutexe und Conditionals, da kein Datenaustausch/Synchronisation zwischen den Threads erforderlich ist. Lass einfach die Threads mit verschiedenen Bereichen der theta Berechnung umgehen.

Mit m=661 und 2 Threads sollte dann der erste Thread theta im Bereich 0.330 berechnen und der zweite Thread sollte theta im Bereich 331..660 berechnen. Starten Sie die zwei Threads und warten Sie, bis sie fertig sind (aka beitreten).

Sie können fast den Singlethread-Code für eine Multithread-Implementierung verwenden. Sie müssen lediglich einen Start-Index zur Funktion hinzufügen.

+0

+1 Abgesehen von dem, was Sie geschrieben haben, verstehe ich auch nicht die Notwendigkeit für while (1) innerhalb der Verarbeitungsfunktion. Und die Verwendung von Mutexes ist völlig unnötig. – Groo

Verwandte Themen