0
votes

I've been trying to use Pthreads in a program to count the 3's in a 3000000 element int array, and when it runs sequentially without using pthreads, it works perfectly.

Using pthreads leads to a segmentation fault and i can't figure out why. the execution stops when each thread reaches around 300000 iteration in case of 4 threads on a 8gb of RAM and 256K L2 cache.

Here is my code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#define LENGTH 3000000
#define NUM_THREADS 4

int countarr[128];
int* array;

struct Op_data{
int start_index;
int count_index;
int CHUNK;
int ID;   
};
void* count3s(void* data) // you need to parallelize this
{
    struct Op_data *info;
        info = (struct Op_data *) data;
    int count_i = info -> count_index;
    int i = info->start_index;
    int CHUNK = info -> CHUNK;
    printf("Thread data:\nCOUNT_INDEX:\t\t%d\nSTART_INDEX:\t\t%d\nCHUNK_SIZE:\t\t%d\n",count_i,i,CHUNK);
    int c = 0;

    struct timeval t1, t2;
    gettimeofday(&t1, NULL);
    for(i;i<i+CHUNK;i++)
    {
        if(array[i]==3)
        {
            c++;
        }
    }
    countarr[count_i] = c;
    gettimeofday(&t2, NULL);
    double t = (t2.tv_sec - t1.tv_sec) + (t2.tv_usec - t1.tv_usec ) / 1000000.0; 
    printf("execution time = %f seconds\n",t);
}
int main(int argc, char * argv[])
{

    int i = 0;
    int ok = 0;
    int count=0;
    array = malloc(LENGTH * sizeof(int));   

        // initialize the array randomly. Make sure the number of 3's doesn't exceed 500000 
    srand(12);

    for(i= 0;i<LENGTH;i++)
        {
        array[i]=rand()%10;

        if(array[i]==3)
                {
            ok++; // keep track of how many 3's are there, we will use this later to confirm the correctness of the code
            if(ok>500000)
                        {
                ok=500000;
                array[i]=12;
            }
        }
    }  
    pthread_t threads[NUM_THREADS];
        struct Op_data* t_data[NUM_THREADS];

        pthread_attr_t attr;
        pthread_attr_init(&attr);

        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    int rc;
    int CHUNK = LENGTH/NUM_THREADS;
    for(int t=0;t<NUM_THREADS;t++)
    {
        t_data[t] = (struct Op_data*) malloc(sizeof(struct Op_data));
        t_data[t] -> start_index = t*CHUNK;
        t_data[t] -> count_index = t*(128/NUM_THREADS);
        t_data[t] -> CHUNK = CHUNK;
        t_data[t] -> ID = t;
        rc = pthread_create(&threads[t], &attr, count3s, (void *)t_data[t]);
        if (rc) {
            printf("Error:unable to create thread,%d\n",rc);
            exit(-1);
            }
    printf("Thread (%d) has been created.\n",t);
    }


    for( int g = 0; g < NUM_THREADS; g++ ) {
        rc = pthread_join(threads[g], NULL);
        if (rc) {
            printf("Error:unable to join,%d\n",rc);
            exit(-1);
        }

    }
    pthread_attr_destroy(&attr);      

        for(int x=0;x<NUM_THREADS;x++)
    {
        count += countarr[x*(128/NUM_THREADS)];
    }

    if( ok == count ) // check if the result is correct
        {
        printf("Correct Result!\n");    
        printf("Number of 3`s: %d\n_________________________________\n",count);
    }
    else
        {
        printf("Wrong Result! Your count:%d\n",count);  
        printf("The correct number of 3`s is: %d\n",ok);
    }
pthread_exit(NULL);
    return 0;
}
1
the posted code causes the compiler to output several warning messages. Always fix warning messages. Always compile with warnings enabled. ( for gcc, at a minimum use: -Wall -Wextra -Wconversion -pedantic -std=gnu11 ) Note: other compilers use different options to produce the same resultsuser3629249
OT: regarding: t_data[t] = (struct Op_data*) malloc(sizeof(struct Op_data)); When calling any of the heap allocation functions: malloc calloc realloc, 1) always check (!=NULL) the returned value to assure the operation was successful. 2) in C, the returned type is void* which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc.user3629249
regarding: srand(12); this will result in the exact same sequence of values from rand() every time the code is executed. Suggest: srand ((unsigned int)time( NULL ) );user3629249
OT: for ease of readability and understanding: Please consistently indent the code: indent after every opening brace '{'. unindent before every closing brace '}'. Suggest each indent level be 4 spaces.user3629249
regarding: ` rc = pthread_create(&threads[t], &attr, count3s, (void *)t_data[t]);` The last parameter should be a pointer. Suggest: ` rc = pthread_create( &threads[ t ], &attr, count3s, (void *)&t_data[ t ] );` notice the additional & before t_data[ t ] Then correct info = (struct Op_data *) data; to actually expect a pointeruser3629249

1 Answers

2
votes
for(i;i<i+CHUNK;i++)

Since i will always be less than i + CHUNK (unless it overflows), this loop will overrun the bounds of the array.