Dan
Dan

Reputation: 437

First threads in array of threads getting skipped in c (sometimes)?

I am trying to write a multithreaded program in C that sorts an array by breaking it up into partitions, and then each thread works on it's own partition. The problem seems to be that sometimes Thread 1, and sometimes Thread 2, get skipped in execution. I haven't even gotten to the sorting, just the comparison. For now i just want to know my threads are running correctly, but it seems the first ones can just not get scheduled or something. I am not very strong with C, and am really racking my brain for what can be going wrong.

I know each thread can be paused by the scheduler, but they all should eventually get completed right? So why does my first couple threads sometimes not run?

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>

#define SIZE 11
#define HM_SORTERS 4

void * sort(void * param);
void printArr(int * arr);

struct PartitionBounds {
    int tid;
    size_t start;
    size_t end;
};

int array[SIZE] = {18, 12, 68, 59, 75, 73, 68, 4, 16, 94, 15};

int main() {

    // srand(time(NULL));
    // for (size_t i = 0; i < SIZE; i++) {
    //     array[i] = rand() % 100;
    // }

    printArr(array);

    pthread_t sorters[HM_SORTERS];

    for(int i=0;i<HM_SORTERS;i++) {
        struct PartitionBounds bounds;
        size_t coverage = SIZE / HM_SORTERS;
        bounds.tid = i;
        bounds.start = i * coverage;
        bounds.end = i + 1 == HM_SORTERS ? SIZE - 1 : bounds.start + coverage - 1;
        int status = pthread_create(&sorters[i], NULL, sort, &bounds);
        if(status == 0) {
            printf("\n--- Thread %d created successfully ---\n", i + 1);
            printf("start: %zu, end: %zu\n", bounds.start, bounds.end);
        } else {
            printf("!!! Failed to create thread !!!\n");
            return 0;
        }
    }

    for(int i=0;i<HM_SORTERS;i++) {
        pthread_join(sorters[i], NULL);
    }

    printf("\n\n----- Sorting completed -----\n\n");

    return 0;
}

void * sort(void * param) {
    struct PartitionBounds *bounds = param;
    printf("\n\tin thread %d\n\n", bounds->tid + 1);
    for(size_t i=bounds->start;i<=bounds->end;i++) {
        for(size_t j=i+1;j<=bounds->end;j++) {
            if(array[j] < array[i]) {
                printf("Thread %d: %d is smaller than %d\n", bounds->tid + 1, array[j], array[i]);
            }
        }
    }
    pthread_exit(NULL);
}

void printArr(int * arr) {
    int coverage = SIZE / HM_SORTERS;
    for(int i=0;i<HM_SORTERS;i++) {
        size_t partitionEnd = i + 1 == HM_SORTERS ? coverage + SIZE % HM_SORTERS : coverage;
        for(int j=0;j<partitionEnd;j++) {
            printf("%d", array[j + coverage * i]);
            if(j+1 < partitionEnd) {
                printf(", ");
            }
        }
        if(i+1 < HM_SORTERS) {
            printf(" | ");  
        }
    }
    printf("\n");
}

output: (typical, when threads get skipped)

18, 12 | 68, 59 | 75, 73 | 68, 4, 16, 94, 15

--- Thread 1 created successfully ---
start: 0, end: 1

--- Thread 2 created successfully ---
start: 2, end: 3

        in thread 1


--- Thread 3 created successfully ---
Thread 3: 73 is smaller than 75

        in thread 3

Thread 3: 73 is smaller than 75

        in thread 2

start: 4, end: 5
Thread 3: 73 is smaller than 75
Thread 4: 68 is smaller than 75
Thread 4: 4 is smaller than 75
Thread 4: 16 is smaller than 75
Thread 4: 15 is smaller than 75

--- Thread 4 created successfully ---
start: 6, end: 10
Thread 4: 68 is smaller than 73
Thread 4: 4 is smaller than 73
Thread 4: 16 is smaller than 73
Thread 4: 15 is smaller than 73
Thread 4: 4 is smaller than 68
Thread 4: 16 is smaller than 68
Thread 4: 15 is smaller than 68
Thread 4: 15 is smaller than 16
Thread 4: 15 is smaller than 94

        in thread 4

Thread 4: 4 is smaller than 68
Thread 4: 16 is smaller than 68
Thread 4: 15 is smaller than 68
Thread 4: 15 is smaller than 16
Thread 4: 15 is smaller than 94


----- Sorting completed -----

Upvotes: 1

Views: 402

Answers (2)

stensal
stensal

Reputation: 401

An alternative solution without using malloc/free .

    struct PartitionBounds bounds[HM_SORTERS];
    ...
        size_t coverage = SIZE / HM_SORTERS;
        bounds[i].tid = i;
        bounds[i].start = i * coverage;
        bounds[i].end = i + 1 == HM_SORTERS ? SIZE - 1 : bounds[i].start + coverage - 1;
        int status = pthread_create(&sorters[i], NULL, sort, &bounds[i]);
    ...

Upvotes: 0

kiran Biradar
kiran Biradar

Reputation: 12732

One problem I do see here is, referring the address of local variable.

    struct PartitionBounds bounds;
    int status = pthread_create(&sorters[i], NULL, sort, &bounds);

bounds is local variable and it will be vanished and new instance will be created on each iteration. Thus referring to it in sort function will have undefined behavior.


What you can do is, dynamically allocate the memory.

 struct PartionBounds *bounds = malloc(sizeof(*bounds));
 int status = pthread_create(&sorters[i], NULL, sort, bounds);

Make sure you free the memory once done.

Upvotes: 1

Related Questions