2016-06-22 12 views
1

Ich habe den folgenden Code geschrieben. Wenn ich einen einzelnen Thread verwende (aa = 1 im Code), dauert es 11 Sekunden. Aber für aa = 2 dauert es 190 Sekunden. Jedoch hat meine Maschine 4 CPUs. Wirst du mir bitte helfen? Ich bin Kompilieren alsLangsame Multithread-Programmierung in C bei mehr als einem Thread

gcc Thread.c O3

#include<stdio.h> 
#include<pthread.h> 
#include <time.h> 
#include<stdlib.h> 



#define N 100 

int aa; 


unsigned long long *reg, *b; 
#define LIMIT 5000000 




void *abc(void* arg){ 
     srand(time(NULL)); 

     unsigned long long i,l; 
     unsigned char z,j; 
     int *limit_ptr=(int *)arg; 
     int i1=*limit_ptr; 
     printf("i1=%d\n",i1); 
     for(l=0;l<LIMIT;l++){ 
      for(i=0;i<N;i++) 
       z=(((double) N)*rand()/(RAND_MAX+1.0));; 

      z = (((double) N)*rand()/(RAND_MAX+1.0));; 

      if(z==0) 
       reg[i1]++; 

     }   

} 

int main(){ 

    int l; 
    aa=2; 
    printf("%d \n\n",aa); 
    reg = (unsigned long long *) malloc(aa * sizeof(unsigned long long)); 
    b = (unsigned long long *) malloc(aa * sizeof(unsigned long long)); 

    struct timespec start, finish; 
    double elapsed; 
    clock_gettime(CLOCK_MONOTONIC, &start); 

    for(l=0;l<aa;l++) 
     reg[l]=0; 
    pthread_t tid[aa]; 

    int j1; 
    unsigned long long cc=0; 



    for(j1=0;j1<aa;j1++) 
     b[j1]=j1; 


    for(j1=0;j1<aa;j1++){ 

     printf("%d\n", j1); 
     pthread_create(&tid[j1],NULL,abc,&b[j1]); 
    } 
//  

    for(j1=0;j1<aa;j1++){ 
     pthread_join(tid[j1],NULL); 
     printf("%d\n", j1); 
    } 

    for(j1=0;j1<aa;j1++)  
     cc=cc+reg[j1]; 


    printf("%0.10f %llu\n", (double)cc/(aa*LIMIT),cc); 

    clock_gettime(CLOCK_MONOTONIC, &finish); 
    elapsed = (finish.tv_sec - start.tv_sec); 
    elapsed += (finish.tv_nsec - start.tv_nsec)/1000000000.0; 

    printf("Time=%0.10f\n", elapsed); 
    pthread_exit(NULL); 

} 

Basierend auf Vorschlag -lpthread, ich habe den Code geändert. Obwohl die Ausführungszeit jetzt in Ordnung ist, ist die Zufallszahlengenerierung nicht in Ordnung. Die Werte des Array-Regs im Code sind gleich. Bitte hilf mir.

#include<stdio.h> 
#include<pthread.h> 
#include <time.h> 
#include<stdlib.h> 
#include <sched.h> 


#define N 100 
#define aa 4 



unsigned long long *reg, *b; 
#define LIMIT 5000000 

int rgen() 
{ 
    int xi; 
    int seed; 
    struct drand48_data drand_buf; 
    double x; 
    static i; 

    if (i==0){ 
     seed = time(NULL); 
     srand48_r(seed, &drand_buf); 
     i = 10; 
    } 

    drand48_r (&drand_buf, &x); 
    xi = (int) (x * 100);  

    return xi; 
} 


void *abc(void* arg){ 
     int l,i, z; 
     int *limit_ptr = (int *) arg; 
     int i1 = *limit_ptr; 

     printf("i1=%d\n",i1); 
     for(l=0; l<LIMIT; l++){ 
       for(i=0; i<N; i++) 
        z= rgen(i1); 

      if(z==0) 
       reg[i1]++; 

     }   

} 

int main(){ 

int l; 

printf("%d \n\n",aa); 
reg = (unsigned long long *) malloc(aa * sizeof(unsigned long long)); 
b = (unsigned long long *) malloc(aa * sizeof(unsigned long long)); 

struct timespec start, finish; 
double elapsed; 
clock_gettime(CLOCK_MONOTONIC, &start); 

for(l=0;l<aa;l++) 
    reg[l]=0; 
pthread_t tid[aa]; 

int j1; 
unsigned long long cc=0; 



for(j1=0;j1<aa;j1++) 
    b[j1]=j1; 


for(j1=0;j1<aa;j1++){ 

    printf("%d\n", j1); 
    pthread_create(&tid[j1],NULL,abc,&b[j1]); 
} 
//  
    printf("created threads\n"); 
    for(j1=0;j1<aa;j1++){ 
    pthread_join(tid[j1],NULL); 
    printf("%d\n", j1); 
    } 

for(j1=0;j1<aa;j1++)  
    cc=cc+reg[j1]; 

printf("\n"); 
for(j1=0;j1<aa;j1++) 
    printf("%llu ", reg[j1]); 

printf("\n"); 

printf("%0.10f %llu\n", (double)cc/(aa*LIMIT),cc); 

clock_gettime(CLOCK_MONOTONIC, &finish); 
elapsed = (finish.tv_sec - start.tv_sec); 
elapsed += (finish.tv_nsec - start.tv_nsec)/1000000000.0; 

printf("Time=%0.10f\n", elapsed); 
pthread_exit(NULL); 


} 
+0

nicht lösen Ihr Problem aber 1) wirft nicht die Ergebnisse eines 'malloc()' 2) Sie nie testen den Rückgabewert von Ihrem 'malloc()' nennt – KevinDTimm

+0

Sie können aber auch das Profil Dein Code, um herauszufinden, wo er die meiste Zeit verbringt. – KevinDTimm

+1

Hav hast du gezählt, wie oft deine Schleife in 'abc()' zusammen mit aa = 1 und mit aa = 2 (von irgendeinem Thread) durchlaufen wird? Sobald Sie haben, kommen Sie zurück und ändern Sie Ihre Frage. Tipp: Deine Threads teilen * keine * Arbeit * – tofro

Antwort

1

muss ich mit diesem mit EOF übereinstimmen: Das Problem sind die Anrufe rand(). Wenn sie durch time(NULL) ersetzt werden, erhalten Sie, was Sie erwarten.

#include<stdio.h> 
#include<pthread.h> 
#include <time.h> 
#include<stdlib.h> 

#define N 100 
#define LIMIT 5000000 

static unsigned long long *reg; 

void *abc(void *arg) 
{ 
    //srand(time(NULL)); 
    unsigned long long i, l, k; 
    unsigned char z; 
    int *limit_ptr = (int *) arg; 
    int i1 = *limit_ptr; 

    printf("Argument: i1=%d\n", i1); 
    k = 0; 

    for (l = 0; l < LIMIT; l++) { 
    for (i = 0; i < N; i++){ 
     z = (((double) N) * time(NULL)/(RAND_MAX + 1.0)); 
     k++; 
    } 
    z = (((double) N) * time(NULL)/(RAND_MAX + 1.0)); 
    if (z == 0) 
     reg[i1]++; 
    } 
    printf("Loops of %d: %lld\n",i1, k); 
    // normal would be pthread_exit() but the linear timings would need 
    // their own function/ extra argument/needless complexity 
    return NULL; 
} 

int main(int argc, char **argv) 
{ 
    int l; 

    struct timespec start, finish; 
    double elapsed_threaded, elapsed_linear; 

    int j1; 
    unsigned long long cc = 0; 

    int num_threads; 

    unsigned long long *b; 

    pthread_attr_t attr; 

    if(argc > 1) 
    num_threads = atoi(argv[1]); // don't use atoi in production 
    else 
    num_threads = 2; 

    printf("# of threads: %d\n", num_threads); 
    // checks omitted here 
    reg = (unsigned long long *) malloc(num_threads * sizeof(unsigned long long)); 
    b = (unsigned long long *) malloc(num_threads * sizeof(unsigned long long)); 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 

    for (l = 0; l < num_threads; l++) 
    reg[l] = 0; 
    pthread_t tid[num_threads]; 

    for (j1 = 0; j1 < num_threads; j1++) 
    b[j1] = j1; 

    clock_gettime(CLOCK_MONOTONIC, &start); 
    for (j1 = 0; j1 < num_threads; j1++) { 
    printf("Thread #%d started\n", j1); 
    // Check omitted 
    pthread_create(&tid[j1], &attr, abc, &b[j1]); 
    } 
    for (j1 = 0; j1 < num_threads; j1++) { 
    // Check omitted 
    pthread_join(tid[j1], NULL); 
    printf("Thread #%d joined\n", j1); 
    } 
    clock_gettime(CLOCK_MONOTONIC, &finish); 

    for (j1 = 0; j1 < num_threads; j1++) 
    cc = cc + reg[j1]; 

    printf("%0.10f %llu\n", (double) cc/(num_threads * LIMIT), cc); 

    elapsed_threaded = (finish.tv_sec - start.tv_sec); 
    elapsed_threaded += (finish.tv_nsec - start.tv_nsec)/1000000000.0; 

    clock_gettime(CLOCK_MONOTONIC, &start); 
    for (j1 = 0; j1 < num_threads; j1++) { 
    abc(&b[j1]); 
    } 
    clock_gettime(CLOCK_MONOTONIC, &finish); 
    elapsed_linear = (finish.tv_sec - start.tv_sec); 
    elapsed_linear += (finish.tv_nsec - start.tv_nsec)/1000000000.0; 

    printf("Time threaded: %0.10f\nTime linear: %0.10f\nRelation %0.10f\n", 
      elapsed_threaded,elapsed_linear, elapsed_threaded/elapsed_linear); 
    pthread_exit(NULL); 
} 

ich es gereinigt ein wenig nach oben (PTHREAD_CREATE_JOINABLE explizit Einstellung ist wahrscheinlich überflüssig, aber überprüfen Sie Ihre Implementierung von pthread sicher zu sein).

Zusammengestellt mit gcc -W -Wall -O3 -g3 thread.c -o thread -lpthread

Ergebnisse mit

1 thread: 
Time threaded: 1.3713400890 
Time linear: 1.3394284740 
Relation 1.0238247996 

2 threads: 
Time threaded: 1.4989349930 
Time linear: 2.6568704750 
Relation 0.5641731530 

3 threads: 
Time threaded: 1.8101585490 
Time linear: 3.9965480710 
Relation 0.4529305082 

4 threads: 
Time threaded: 1.3974386710 
Time linear: 5.3152423440 
Relation 0.2629115627 

5 threads: 
Time threaded: 1.7717215210 
Time linear: 6.6438871330 
Relation 0.2666694189 

Sie jetzt erraten können, wie viele Kerne meine CPU hat.

PS: bitte implementieren alle Kontrollen, auch wenn Sie experimentieren, besonders wenn Sie experimentieren. Diese

+0

Danke. Aber ((Doppel) N) * Zeit (NULL)/(RAND_MAX + 1.0)) gibt keine zufälligen Werte. – user12290

+0

@ user12290 das war nur für das Problem der Thread-Sicherheit. Eine thread-sichere Variante von 'rand (3)' ist 'rand_r (3)', aber das ist seit Posix-2008 obsolet geworden, also ist es entweder eine von '[dlenmj] rand48_r (3) 'oder roll-your-own. – deamentiaemundi