Search code examples
cconcurrencyparallel-processingpthreadsposix

How to get one correct value from a function which is parallelized by multi-threads


For faster calculation, trying to make my method parallelized by 4 threads. Where threads are making 4 separate calculation whether I was expecting concurrent operation and on single variable.

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

static int x, j=5;

void *print_count (void *dummy)
{
  for(int i=0;i<1000;i++){
  x+=j;
  }
}

int main ()
{
pthread_t p1, p2, p3, p4;

pthread_create (&p1, NULL, print_count, NULL);
pthread_create (&p2, NULL, print_count, NULL);
pthread_create (&p3, NULL, print_count, NULL);
pthread_create (&p4, NULL, print_count, NULL);

pthread_join (p1, NULL);
pthread_join (p2, NULL);
pthread_join (p3, NULL);
pthread_join (p4, NULL);

printf("Actual output: %d \nExpected output: 5000\n", x);

return 0;

}

I expect the output 5000 as the increment is 5 and loop for 1000 times. But the actual output first of all not static, it always change and it is near 4 times of 5000 because threads are calculating the print_count separately.

Thank you


Solution

  • If you are under C11 you can use _Atomic

    Of course each thread needs to work over a range of values (not with the complete set), pass a struct:

    #include <stdio.h>
    #include <stdatomic.h>
    #include <pthread.h>
    
    _Atomic int x;
    static int j = 5;
    
    struct range {
        int from, to;
    };
    
    void *print_count(void *data)
    {
        struct range *range = data;
    
        for (int i = range->from; i < range->to; i++) {
            x += j;
        }
        return NULL;
    }
    
    int main(void)
    {
        pthread_t p1, p2, p3, p4;
        struct range ranges[] = {
            {0, 250},
            {250, 500},
            {500, 750},
            {750, 1000}
        };
    
        pthread_create(&p1, NULL, print_count, &ranges[0]);
        pthread_create(&p2, NULL, print_count, &ranges[1]);
        pthread_create(&p3, NULL, print_count, &ranges[2]);
        pthread_create(&p4, NULL, print_count, &ranges[3]);
    
        pthread_join(p1, NULL);
        pthread_join(p2, NULL);
        pthread_join(p3, NULL);
        pthread_join(p4, NULL);
    
        printf("Actual output: %d \nExpected output: 5000\n", x);
        return 0;
    }
    

    Or a compound literal:

    pthread_create(&p1, NULL, print_count, (int []){  0,  250});
    pthread_create(&p2, NULL, print_count, (int []){250,  500});
    pthread_create(&p3, NULL, print_count, (int []){500,  750});
    pthread_create(&p4, NULL, print_count, (int []){750, 1000});
    
    ...
    
    void *print_count(void *data)
    {
        int *range = data;
    
        for (int i = range[0]; i < range[1]; i++) {
            x += j;
        }
        return NULL;
    }
    

    in order to divide the task.

    Output:

    Actual output: 5000 
    Expected output: 5000