1

我对线程很陌生,想要一些见解。我正在尝试获取每个线程已完成计算的百分比。每个线程都会将其百分比报告给同一数组的不同元素。我在此pthread_join之后立即使用它,pthread_create并使用一个单独的线程来读取数组的所有值并打印百分比,但是当我让所有线程相互运行而不等待前一个线程完成时,我会得到一些奇怪的行为。这就是我访问共享(全局)数组的方式。

//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);
}

}

4

1 回答 1

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

上面提到的不同步访问会影响percent值的计算,从而导致这种异常的发生。您必须在所有这些地方进行同步才能获得您期望的那种行为。

于 2012-10-13T09:43:25.717 回答