2012-10-13 42 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