2012-10-13 45 views
1

我很新的线程,并希望有一些见解。我试图获得每个线程完成计算的百分比。每个线程都会将其百分比报告给同一阵列的不同元素。我在pthread_create之后立即与pthread_join一起工作,并且有一个单独的线程用于读取数组的所有值并打印百分比,但是当所有线程都相继运行而没有等待前一个线程完成时,会出现一些奇怪的行为。这就是我访问共享(全局)数组的方式。从线程读取数组,c,cygwin

//global 
int *currentProgress; 
//main 
    currentProgress = malloc(sizeof(int)*threads); 
    for(i=0; i<threads; i++) 
     currentProgress[i] = 0; 
//child threads 
currentProgress[myId] = (int)percent; //myId is unique 

//progress thread 
for(i=0; i<threads; i++) 
    progressTotal += currentProgress[i]; 
progressTotal /= threads; 
printf("Percent: %d", progressTotal); 

这实质上是我认为没有正确使用多线程的代码。当我打印出共享数组的状态时,我注意到,一旦另一个线程开始访问数组(不同的元素,虽然),前一个元素立即去到一些随机数... -2147483648,当后一个元素完成事先元素像正常一样继续。我应该为此使用信号量吗?我以为我可以同时访问数组中的不同元素,并且我认为阅读它们不是问题。

这是整个代码:

#include <stdlib.h> 
#include <stdio.h> 
#include <math.h> 
#include <stdint.h> 
#include <pthread.h> 
#include <string.h> 

#define STDIN 0 


int counter = 0; 
uint64_t *factors; 
void *getFactors(void *arg); 
void *deleteThreads(void *arg); 
void *displayProgressThread(void *arg); 
int *currentProgress; 

struct data 
{ 
    uint64_t num; 
    uint64_t incrS; 
    uint64_t incrF; 
    int threads; 
    int member; 
} *args; 

int main(int argc, char *argv[]) 
{ 

    if(argc < 3) {printf("not enough arguments"); exit(1);} 

    int i; 
    int threads = atoi(argv[2]); 
    pthread_t thread_id[threads]; 
    pthread_t dThread; 

    currentProgress = malloc(sizeof(int)*threads); 
    for(i=0; i<threads; i++) 
     currentProgress[i] = 0; 

    args = (struct data*)malloc(sizeof(struct data)); 
    args->num = atoll(argv[1]); 
    args->threads = threads; 

    uint64_t increment = (uint64_t)sqrt((uint64_t)args->num)/threads; 
    factors = (uint64_t*)malloc(sizeof(uint64_t)*increment*threads); 

    pthread_create(&dThread, NULL, displayProgressThread, (void*)args); 

    //for the id of each thread 
    args->member = 0; 
    for(i=0; i<threads; i++) 
    { 
      args->incrS = (i)*increment +1; 
      args->incrF = (i+1)*increment +1; 
      pthread_create(&thread_id[i], NULL, getFactors, (void*)args); 
      usleep(5); 
    } 

    for(i=0; i<threads; i++) 
    { 
     pthread_join(thread_id[i], NULL); 
    } 
    sleep(1); 
    printf("done\n"); 
    for (i=0; i<counter; i++) 
     printf("\n%llu : %llu", factors[++i], factors[i]); 
    return 0; 
} 

void *getFactors(void *arg) 
{ 
    uint64_t count; 
    int myId; 
    int tempCounter = 0, i; 
    struct data *temp = (struct data *) arg; 
    uint64_t number = temp->num; 
    float total = temp->incrF - temp->incrS, percent; 

    myId = temp->member++; 

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 

    for(count=temp->incrS; count<=temp->incrF; count++) 
    { 

     percent = (float)(count-temp->incrS)/total*100; 
     currentProgress[myId] = (int)percent; 

     if (number%count == 0) 
     { 
       factors[counter++] = count; 
       factors[counter++] = number/count; 
     } 
     usleep(1); 
    } 
    usleep(1); 
    pthread_exit(NULL); 
} 

void *displayProgressThread(void *arg) 
{ 
    struct data *temp = (struct data *) arg; 
    int toDelete = 0; 
    while(1) 
    { 
     int i; 
     int progressTotal = 0; 
     char *percent = malloc(sizeof(char)*20); 
     for(i=0; i<toDelete; i++) 
      printf("\b \b"); 

     for(i=0; i<temp->threads; i++){ 
      progressTotal += currentProgress[i]; 
     } 

     progressTotal /= temp->threads; 
     printf("|"); 
     for(i=0; i<50; i++) 
      if(i<progressTotal/2) 
       printf("#"); 
      else 
       printf("_"); 
     printf("| "); 
     sprintf(percent, "Percent: %d", progressTotal); 
     printf("%s", percent); 
     toDelete = 53 + strlen(percent); 


usleep(1000); 
    fflush(stdout); 
    if(progressTotal >= 100) 
     pthread_exit(NULL); 
} 

}

+0

我想你必须把完整的代码放在这里,因为做事的顺序很重要。 – RGO

回答

1

但是也有一些通过引起该问题的线程访问的代码一些非同步块。

一个首先要同步的是:

myId = temp->member++; 

但更重要的是,主线程正在做:

args->incrS = (i)*increment +1; 
    args->incrF = (i+1)*increment +1; 

而在线程在同一时间:

for(count=temp->incrS; count<= temp->incrF; count++) 
    { 

     percent = (float)(count-temp->incrS)/total*100; 
     currentProgress[myId] = (int)percent; 

     if (number%count == 0) 
     { 
       factors[counter++] = count; 
       factors[counter++] = number/count; 
     } 
     usleep(1); 
    } 

上面提到的不同步访问影响了的计算导致这种异常事件的值。你必须在所有这些地方进行同步,以获得你期望的行为。

+0

谢谢。我看到问题的标识部分,但完全覆盖了增量。我正在使用互斥锁和条件变量编写一个sem类,但直到那时我才会将这些分配给新数据,并让主线程在发生这种情况时睡一会儿。 – RileyVanZeeland

+0

我建议将所有并发的“读/写”操作移动到一些正确同步的方法。与此同时,在'for'循环之前将'temp-> incrS'和'temp-> incrF'获取到某些局部变量**并在循环**中使用这些变量也可能有所帮助。 – RGO