Reputation: 437
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
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
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