mariya
mariya

Reputation: 295

Calculate series with multithreading in C doesn't work as expected

I am trying to write a program in C that calculates the series:

for(i=0; i <= n; i++){ (2*i+1)/factorial(2*i); }

n is the number of elements, determined by the user as an argument. The user also determines the number of threads that are going to calculate the series.

I divide the series in subseries that calculate only a part of the series and each subseries should be calculated by a single thread. The problem is that my threads probably share memory because some series members are calculated many times and others are not calculated at all. Do you know why? Please help!

Here is the problematic part of the code:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <gmp.h>
#include <math.h>
#include <pthread.h>

/* a struct to pass function arguments to the thread */
struct intervals_struct {
    int **intervals;
    mpf_t *result;
    int thread_index;
};

/* calculate the sum of the elements of the subseries;
doesn't work properly for more than one thread */
void* sum_subinterval(void *args) {
    /* Initialize the local variables here */

    struct intervals_struct *p = (struct intervals_struct*)args;

    for(i=(*p).intervals[(*p).thread_index][0]; i<=(*p).intervals[(*p).thread_index][1]; i++){
        /* Do something with the local variables here */
    }

    mpf_set((*p).result[(*p).thread_index],sum);

    /* Free resources used by the local variables here */
}

/* calculate the sum of all subseries */     
void main(int argc, char * argv[]){
    int p, t, i;

    p = atoi(argv[1]);
    assert( p >= 0);

    t = atoi(argv[2]);
    assert( t >= 0);

    int **intervals_arr;

    intervals_arr = (int**)malloc(t * sizeof(int *));
    for(i = 0; i < t; i++) {
        intervals_arr[i] = (int *)malloc(2 * sizeof(int));
    }

    /* Calculate intervals and store them in intervals_arr here */

    mpf_t *subinterval_sum;
    subinterval_sum = (mpf_t*)malloc(t * sizeof(mpf_t));
    for(i=0; i < t; i++) {
        mpf_init(subinterval_sum[i]);
    }

    pthread_t *tid;
    tid = (pthread_t *)malloc(t * sizeof(pthread_t));

    for(i = 0; i < t; i++) {
        struct intervals_struct args = {intervals_arr, subinterval_sum, i};
        pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args);
    }

    for(i = 0; i < t; i++) {
        pthread_join(tid[i], NULL);
    }

    /* Sum the elements of the result array and free resources used in main here */
}  

Upvotes: 0

Views: 165

Answers (1)

T.C.
T.C.

Reputation: 137345

The problem is probably here:

for(i = 0; i < t; i++) {
    struct intervals_struct args = {intervals_arr, subinterval_sum, i};
    pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args);
}

You are passing the address of args to your new thread, but the lifetime of that variable ended immediately after the pthread_create call. The compiler can and will reuse the stack space occupied by args between different loop iterations.

Try allocating an array on the heap with malloc instead.

Edit: What I meant by that last sentence is something like this:

struct intervals_struct * args = (struct intervals_struct *) calloc(t, sizeof(struct intervals_struct));

for(i = 0; i < t; i++) {
    args[i].intervals = intervals_arr;
    args[i].result = subinterval_sum;
    args[i].thread_index = i;
    pthread_create(&(tid[i]), NULL, sum_subinterval, (void*)&args[i]);
}

// at the end of main(), or at least after every thread has been joined
free(args);

Upvotes: 3

Related Questions