I am trying to work with threads in C. I need one of my threads to work on one half of a whole array, and mergesort its half. To do this I created a global array pointer for the whole array and both halves. The is allocated at runtime with malloc.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
void *process1(void *arg);
void *process2(void *arg);
void *process3(void *arg);
void *process4(void *arg);
void *process5(void *arg);
void merge(int *arr, int l, int m, int r);
void mergeSort(int *arr, int l, int r);
int *array;
int *arr_first;
int *arr_second;
int arr_s;
size_t n_size;
int n_size_i;
pthread_mutex_t mutex;
main(int argc, char *argv[]) {
arr_s = atoi(argv[1]);
n_size = arr_s / 2;
n_size_i = arr_s / 2;
array = malloc (arr_s * sizeof (int));
arr_first = malloc(arr_s / 2 * sizeof(int));
if (arr_s % 2 == 0)
arr_second = malloc((n_size) * sizeof (int));
else
arr_second = malloc((n_size+1) * sizeof(int));
pthread_t tid1, tid2, tid3, tid4, tid5;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_mutex_init(&mutex, NULL);
pthread_create(&tid1, &attr, process1, NULL);
pthread_join(tid1, NULL);
printf("---------------------------------------------------------------------------THREAD 2 AND 3 ARE CURRENTLY SORTING THE NUMBERS-------------------------------------------------------------------------\n");
pthread_create(&tid2, &attr, process2, NULL);
pthread_create(&tid3, &attr, process3, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_create(&tid4, &attr, process4, NULL);
pthread_join(tid4, NULL);
pthread_create(&tid5, &attr, process5, NULL);
pthread_join(tid5, NULL);
free(array);
free(arr_first);
free(arr_second);
exit(0);
}
Here is what the function looks like for my thread im having trouble on (thread 2) At the moment, all it does it takes the first half of the whole array, and one by one takes the value and places it into its own. Then i print out the array. Then finally call mergesort on the array pointer.
void *process2(void *arg) {
int j = 0;
for (; j < (arr_s / 2); j++) {
arr_first[j] = array[j];
}
int j2;
for (j2 = 0; j2 < (arr_s / 2); j2++) {
printf("*%d\t", arr_first[j2]);
if ((j2 + 1) % 25 == 0 && j2 > 0)
printf("\n");
}
mergeSort(arr_first, 0, (arr_s / 2) - 1);
pthread_exit (0);
}
Here are my merge and mergeSort functions:
//Merges two subarrays of arr[]
//First subarry is arr[l..m]
//Second subarry is arr[m+1..r]
void merge(int *arr, int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
//create temp arrays
int L[n1], R[n2];
//copy data to temp array L[] and R[]
for (i = 0; i < n1; i++)
L[i] = arr[l+i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
//merge the temp arrays back in arr[l..r]
i = 0; j = 0; k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
//copy remaining elements of L[], if there are any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
//same for R[]
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int *arr, int l, int r) {
if (l < r) {
int m = 1 + (r - 1) / 2;
//Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
For some reason when I call merge sort, it will keep recursively calling many more times than there are even elements in the array. I put a print statement before anything else in the mergeSort function, and the print statement executes 50000+ times maybe more. However, if I put a print statement right before the merge call inside mergeSort it never gets executed.
The computation for the middle point in mergeSort is incorrect: there is a confusion between l and 1. It should be:
int m = l + (r - l) / 2;
Naming a variable l is very error prone. Use left or low instead:
void mergeSort(int *arr, int left, int right) {
if (left < right) {
int m = left + (right - left) / 2;
//Sort first and second halves
mergeSort(arr, left, m);
mergeSort(arr, m + 1, right);
merge(arr, left, m, right);
}
}
Related
I wrote a program that implements the mergeSort algorithm, which sorts across multiple threads.
The algorithm is able to spread the sorted vector over several threads
The program contains mutexes to protect global counters that are incremented by each thread.
I would like you to help me modify the program so that I do not use so many global variables. I also think that the program is making too many copies and that problems may occur
#include <stdio.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
pthread_mutex_t mutex_p = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_pi = PTHREAD_MUTEX_INITIALIZER;
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
int idx[20]; // hold the right end at each vector subdivision
int p_i = 0;
int *a;
int part = 0;
// mergeSort function to interclass two parts
void merge(int l1, int h1, int h2)
{
int count = h2 - l1 + 1;
int sorted[count];
int i = l1, k = h1 + 1, m = 0;
while (i <= h1 && k <= h2)
{
if (a[i] < a[k])
sorted[m++] = a[i++];
else if (a[k] < a[i])
sorted[m++] = a[k++];
else if (a[i] == a[k])
{
sorted[m++] = a[i++];
sorted[m++] = a[k++];
}
}
while (i <= h1)
sorted[m++] = a[i++];
while (k <= h2)
sorted[m++] = a[k++];
for (i = 0; i < count; i++, l1++)
a[l1] = sorted[i];
}
// mergeSort function
void merge_sort(int low, int high)
{
// calculates the middle of the array
int mid = low + (high - low) / 2;
if (low < high)
{
// I call the first half
merge_sort(low, mid);
// I call the second half
merge_sort(mid + 1, high);
// interclassification between the two halves
merge(low, mid, high);
}
}
// thread function for multi-threading
void *mergeSort(void *arg)
{
pthread_mutex_lock(&mutex_p);
int thread_part = part++;
pthread_mutex_unlock(&mutex_p);
// calculate the minimum and maximum
int low = thread_part * (MAX / THREAD_MAX);
int high = (thread_part + 1) * (MAX / THREAD_MAX) - 1;
// allocate the rest of the original array to the last thread
if (thread_part == THREAD_MAX - 1)
{
high = MAX - 1;
}
// stores the right edge for each split array
pthread_mutex_lock(&mutex_pi);
idx[++p_i] = high;
pthread_mutex_unlock(&mutex_pi);
// calculate the midpoint
int mid = low + (high - low) / 2;
merge_sort(low, mid);
merge_sort(mid + 1, high);
merge(low, mid, high);
return NULL;
}
void isSorted(int len)
{
if (len == 1)
{
printf("Sorting completed\n");
return;
}
int i;
for (i = 1; i < len; i++)
{
if (a[i] < a[i - 1])
{
printf("Sorting is not complete\n");
return;
}
}
printf("Sorting completed\n");
return;
}
// The main program
int main()
{
printf("Enter the number of items in the array:");
scanf("%d", &MAX);
printf("Enter the number of threads you want:");
scanf("%d", &THREAD_MAX);
// generates random number in array up to 1000
a = malloc(MAX * sizeof(int));
srand(time(NULL));
for (int i = 0; i < MAX; i++)
{
a[i] = rand() % 1000;
}
// t1 and t2 to calculate the time to mergeSort
clock_t t1 = clock();
pthread_t threads[THREAD_MAX];
// thread creation
for (int i = 0; i < THREAD_MAX; i++)
{
pthread_create(&threads[i], NULL, mergeSort, (void *)NULL);
}
// joining all threads
for (int i = 0; i < THREAD_MAX; i++)
{
pthread_join(threads[i], NULL);
}
// merging on the last elements
int p = 1;
int mid, high;
for (int q = 1; q < THREAD_MAX; q++)
{
mid = idx[p];
p++;
high = idx[p];
merge(0, mid, high);
}
clock_t t2 = clock();
printf("Time required: %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
isSorted(MAX);
//sorted array display
printf("Sorted array: ");
for (int i = 0; i < MAX; i++)
printf("%d ", a[i]);
printf("\n");
free(a);
return 0;
}
The key to remove global variable is to locally pass data from functions to functions. First of all, pthread_create have a parameter called arg which enable you to pass a structure with many fields in argument to the created thread. The idea is to declare a structure like this:
// TODO: check all the fields are actually needed
struct ThreadContext
{
pthread_mutex_t mutex_p;
pthread_mutex_t mutex_pi;
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
int idx[20]; // hold the right end at each vector subdivision
int p_i = 0;
int *a;
int part = 0;
};
Then create it on the stack, then fill it (typically the mutex fields), before creating threads, and finally pass it to the threads using:
// &your_struct is a pointer to your_struct
pthread_create(&threads[i], NULL, mergeSort, (void*)&your_struct);
Your mergeSort function can then extract the data structure from the void* pointer.
void* mergeSort(void* arg)
{
struct ThreadContext* context = (struct ThreadContext*)arg;
pthread_mutex_lock(&context.mutex_p); // Example of usage
// [...]
}
You can also add new parameters to the merge and merge_sort functions if needed.
Note that int idx[20]; can be replaced by int* idx and allocated dynamically (using malloc and free) so not to have a predetermined limit to the number of threads that can be used in your program.
I am surprised to see mutexes in a merge sort. Indeed, the idea of a parallel merge sort is to split the work between thread so each work on different data. As a result, there is no need for critical sections. You can use the thread ID to select with thread do the merge instead of preventing other threads to do operations with critical sections.
Note that you can create an array of ThreadContext and fill it with different data so each thread have different information (filled by the main thread). For example, the thread ID can be different as well as the start/stop indices. This help you not to use any mutexes in your code. To avoid the replication of some fields in each thread you can even split the structure into 3 different structures:
struct SharedContext
{
// Shared fields like the number of threads, the array pointer, the total number of element, mutexes (if any), etc.
};
struct PrivateContext
{
// Thread private fields like the thread ID, the start/stop indices, etc.
};
struct ThreadContext
{
struct SharedContext* sharedCtx;
struct PrivateContext privateCtx;
};
Note that sharedCtx should be filled with the pointer to a SharedContext structure created by the main thread (eg. allocated on the stack).
You can remove the global variables by passing the appropriate arguments to each thread.
For this, you can define an array of structures, one for each thread, populate it with arguments before launching the thread and pass the structure pointer to pthread_create.
With each thread acting on its own data, you no longer need the global variables, nor even the mutexes.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
struct thread_data {
int *a;
int low;
int high;
};
// mergeSort function to interclass two parts
void merge(int *a, int lo, int mid, int hi) {
int count = hi - lo;
int sorted[count];
int i = lo, k = mid, m = 0;
while (i < mid && k < hi) {
if (a[i] <= a[k])
sorted[m++] = a[i++];
else
sorted[m++] = a[k++];
}
while (i < mid)
sorted[m++] = a[i++];
for (i = 0; i < m; i++)
a[lo + i] = sorted[i];
}
// mergeSort function
void merge_sort(int *a, int low, int high) {
// calculates the middle of the array
int mid = low + (high - low) / 2;
if (high - low > 1) {
// I call the first half
merge_sort(a, low, mid);
// I call the second half
merge_sort(a, mid, high);
// interclassification between the two halves
merge(a, low, mid, high);
}
}
// thread function for multi-threading
void *mergeSort(void *arg) {
struct thread_data *data = arg;
merge_sort(data->a, data->low, data->high);
return NULL;
}
void isSorted(const int *a, int len) {
for (int i = 1; i < len; i++) {
if (a[i] < a[i - 1]) {
printf("Sorting is not complete\n");
return;
}
}
printf("Sorting completed\n");
}
void printArray(const int *a, int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
// The main program
int main() {
int *a; // array pointer
int MAX; // number of elements in the array
int THREAD_MAX; // number of threads
printf("Enter the number of items in the array:");
if (scanf("%d", &MAX) != 1)
return 1;
printf("Enter the number of threads you want:");
if (scanf("%d", &THREAD_MAX) != 1)
return 1;
// generates random number in array up to 1000
a = malloc(MAX * sizeof(int));
srand(time(NULL));
for (int i = 0; i < MAX; i++) {
a[i] = rand() % 1000;
}
// t1 and t2 to calculate the time to mergeSort
clock_t t1 = clock();
// thread creation
pthread_t threads[THREAD_MAX];
struct thread_data data[THREAD_MAX];
for (int i = 0; i < THREAD_MAX; i++) {
data[i].a = a;
data[i].low = i * MAX / THREAD_MAX;
data[i].high = (i + 1) * MAX / THREAD_MAX;
pthread_create(&threads[i], NULL, mergeSort, &data[i]);
}
// joining all threads
for (int i = 0; i < THREAD_MAX; i++) {
pthread_join(threads[i], NULL);
}
// merging on the last elements
// this merge phase is inefficient
for (int i = 1; i < THREAD_MAX; i++) {
int mid = data[i].low;
int high = data[i].high;
merge(a, 0, mid, high);
}
clock_t t2 = clock();
printf("Time required: %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
isSorted(a, MAX);
//sorted array display
if (MAX < 100) {
printf("Sorted array: ");
printArray(a, MAX);
}
free(a);
return 0;
}
I'm having issues with getting my mergeSort algorithm to work properly. The code is below, but I'll briefly summarize what I have tried and what I know is not wrong with the code.
The mergeSort function takes a pointer to an array and the array's size as arguments. If the size of the array is less than 2, it returns immediately. I'm sure that this works, because I debugged this part several times. It returns 8 times, which is what I expected it to do.
Next, a variable mid is created as an index to split the array by. I tested it, and I'm pretty confident that mid is correct across all recursions. Then, two arrays are created, the first containing the elements from the indexes 0...mid-1 and the second containing the elements from the indexes mid to n. Next, the sizes of each of these arrays are computed. I tested this too, and the sizes seem correct across all recursions as well. mergeSort is called on the left array and the right array, and then merge is called.
The actual merge function takes a pointer to the original array, a pointer to the left array, a pointer to the right array, and two integer values which are the sizes of each of the left and right arrays. Then, it compares the elements in L and R and copies the smaller of the two into A, in order.
My output, however, is [2] [4] [1] [6] [8] [5] [3] [7]
My expected output is: [1] [2] [3] [4] [5] [6] [7] [8]
I'm genuinely not sure why the code isn't working. There's probably something I'm overlooking, but I've been trying to solve it for an hour and figured I'd ask for help.
If you take the time to answer, or attempt to answer this question, thank you for your time.
My code is below:
#include <stdio.h>
#include <stdlib.h>
void mergeSort(int *, int);
void merge(int *, int *, int, int *, int);
void print(int *, int);
int main() {
int A[8] = { 2, 4, 1, 6, 8, 5, 3, 7 };
int arraySize = sizeof(A) / sizeof(A[0]);
mergeSort(A, arraySize);
print(A, arraySize);
}
void mergeSort(int *A, int n) {
if (n < 2) {
return;
}
int mid = n / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++) {
L[i] = A[i];
}
for (int j = mid; j < n; j++) {
R[j - mid] = A[j + mid + 1];
}
int leftSize = sizeof(L) / sizeof(L[0]);
int rightSize = sizeof(R) / sizeof(R[0]);
mergeSort(L, leftSize);
mergeSort(R, rightSize);
merge(A, L, leftSize, R, rightSize);
}
void merge(int *A, int *L, int leftSize, int *R, int rightSize) {
int i, j, k;
while (i < leftSize && j < rightSize) {
if (L[i] < R[j]) {
A[k] = L[i];
k++;
i++;
} else {
A[k] = R[j];
k++;
j++;
}
}
}
void print(int *A, int n) {
for (int i = 0; i < n; i++) {
printf("[%d] ", A[i]);
}
printf("\n");
}
There are multiple problems:
the intialization loop for R is incorrect: you should copy A[j] instead of A[j + mid + 1]
the merge function should copy the remaining elements from the left or right arrays once the test i < leftSize && j < rightSize fails.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
void mergeSort(int *, int);
void merge(int *, int *, int, int *, int);
void print(const int *, int);
int main() {
int A[8] = { 2, 4, 1, 6, 8, 5, 3, 7 };
int arraySize = sizeof(A) / sizeof(A[0]);
mergeSort(A, arraySize);
print(A, arraySize);
return 0;
}
void mergeSort(int *A, int n) {
if (n < 2) {
return;
}
int mid = n / 2;
int L[mid];
int R[n - mid];
for (int i = 0; i < mid; i++) {
L[i] = A[i];
}
for (int j = mid; j < n; j++) {
R[j - mid] = A[j];
}
int leftSize = sizeof(L) / sizeof(L[0]);
int rightSize = sizeof(R) / sizeof(R[0]);
mergeSort(L, leftSize);
mergeSort(R, rightSize);
merge(A, L, leftSize, R, rightSize);
}
void merge(int *A, int *L, int leftSize, int *R, int rightSize) {
int i, j, k;
while (i < leftSize && j < rightSize) {
if (L[i] <= R[j]) {
A[k++] = L[i++];
} else {
A[k++] = R[j++];
}
}
while (i < leftSize) {
A[k++] = L[i++];
}
while (j < rightSize) {
A[k++] = R[j++];
}
}
void print(const int *A, int n) {
for (int i = 0; i < n; i++) {
printf("[%d] ", A[i]);
}
printf("\n");
}
I am trying to modify this merge sort codes from GeekstoGeeks with passing an array by reference.
/* C program for Merge Sort */
#include <stdio.h>
#include <stdlib.h>
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int L[n1], R[n2];
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0; // Initial index of first subarray
j = 0; // Initial index of second subarray
k = l; // Initial index of merged subarray
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
}
else {
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there
are any */
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there
are any */
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r)
{
if (l < r) {
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m = l + (r - l) / 2;
// Sort first and second halves
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size)
{
int i;
for (i = 0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
/* Driver program to test above functions */
int main()
{
int arr[] = { 12, 11, 13, 5, 6, 7 };
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("Given array is \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("\nSorted array is \n");
printArray(arr, arr_size);
return 0;
}
To something like this:
void mergeSort(int* arr[], int l, int r);
void merge(int* arr[], int l, int m, int r);
I thought it is a simple task because I could simply change every arr to *arr in the functions to dereference them. The program is still runnable but gives me a bunch of unknown numbers.
Then I searched the stack overflow until I see this post:
https://stackoverflow.com/questions/49751409/swapping-2-arrays-in-c#:~:text=Since%20pointer%20is%2064%20bit,two%20int%20which%20get%20swapped.&text=In%20C%20an%20array%20is,they%20are%20pointers%20to%20arrays
It also passes an array by reference. (int* a and int* b)
void swapArray( int *a, int *b, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
But in reverse, when I change it to
void swapArray( int a, int b, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
int tmp = a[i];
a[i] = b[i];
b[i] = tmp;
}
}
It doesn't work, again. Could someone explain to me why and how can I modify my merge sort codes properly? Or where I should look for? I am so confused about this. Any help is appreciated.
int *arr[] is an array of pointers. Or rather it's a pointer to a pointer (it's really int **arr).
To pass a pointer to an array (which almost never is needed) you need e.g. int (*arr) [6]. And yes, the size of the array is then mandatory (variable-length arrays are valid).
But as I said, passning pointers to arrays is almost never needed, because arrays naturally decays to pointers (to their first element).
And as an argument declaration int arr[] is equal to int *arr.
That is, with
void merge(int arr[], int l, int m, int r)
you already pass the array by "reference".
The subscript operator, [ ], has higher precedence than the dereference operator, *. So int *arr[] declares arr to be an array of pointers to int. To make it a pointer to an array, you need int (*arr)[].
Similarly, in expressions, *arr[3] attempts to take element 3 of an array arr and dereference it. Instead you need (*arr)[3] to use *arr to get the array and then [3] to get element 3.
I have been taking a class at Coursera and we had an assignment which was to count the number of comparisons QuickSort does on a 10,000 size array a numbers.
#include <stdio.h>
#define SIZE 10000
int ComparsionCount = 0;
void swap(int a[], int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
int partition(int a[], int l, int r){
int p = a[l];
int i = l + 1;
int j;
for (j = l + 1; j <= r; j++) {
if (a[j] < p) {
swap(a, j, i);
i++;
}
}
swap(a, l, i - 1);
return (i - 1);
}
void add(int i) {
ComparsionCount += i;
}
int QuickSort(int a[], int l, int r){
int pivot;
if (r > 1) {
add(r - 1);
pivot = partition(a, l, r);
QuickSort(a, l, pivot - 1);
QuickSort(a, pivot + 1, r);
}
return pivot;
}
int main() {
FILE *fr;
int arr[SIZE];
int i = 0;
int elapsed_seconds;
char line[80];
fr = fopen("QuickSort.txt", "r");
while (fgets(line, 80, fr) != NULL)
{
/* get a line, up to 80 chars from fr. done if NULL */
sscanf (line, "%ld", &elapsed_seconds);
/* convert the string to a int */
arr[i] = atoi(line);
i++;
}
fclose(fr); /* close the file prior to exiting the routine */
printf("%d\n",QuickSort(arr,0,SIZE-1));
}
I am getting an segmentation error. I have identified that the problem lies in two recursive calls of QuickSort.
I have no idea of how to solve this problem,your help would be appreciated a lot
Thanks in advance.
I think you should add the code in the partition function like this:
for (j = l + 1; j <= r; j++) {
count++;
if (a[j] < p) {
...
}
Note: count is a global variable initialized to 0.
I'm learning how to parallize the merge sort in C following this tutorial
http://elc.yonsei.ac.kr/courses/csi2110/PP-L05-ScalableAlgorithmicTechniques.pdf But it only works sometimes. I run the code in the terminal about 10 times, and sometimes I get segmentation fault, other times, I get random numbers in my array, or sometimes, it works.
I'm not sure where I'm going wrong so any help would indeed be most appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>
pthread_t LThread;
pthread_t RThread;
void MergeSort(float A[], int p, int r);
void ParallelMergeSort(float A[], int p, int r, int depth, int max_depth);
void Merge(float A[], int p, int q, int r);
struct arg {
float* A;
int p;
int r;
int depth;
int max_depth;
};
void* PMSort(void* ptr){
struct arg* MyArg = (struct arg*) ptr;
ParallelMergeSort(MyArg->A, MyArg->p, MyArg->r, MyArg->depth, MyArg->max_depth);
return 0;
}
void ParallelMergeSort(float A[], int p, int r, int depth, int max_depth){
if (depth == max_depth){
MergeSort(A, p, r);
}
else {
/*
1) Spawn 2 threads for left and right sub array
2) Join the 2 threads
3) Perform the merge
*/
int q;
if (p < r){
q = (p+r) / 2;
struct arg* LeftArg = malloc(sizeof(struct arg));
struct arg* RightArg = malloc(sizeof(struct arg));
LeftArg->A = A;
LeftArg->p = p;
LeftArg->r = q;
LeftArg->depth = depth + 1;
LeftArg->max_depth = max_depth;
RightArg->A = A;
RightArg->p = q + 1;
RightArg->r = r;
RightArg->depth = depth + 1;
RightArg->max_depth = max_depth;
pthread_create(<hread, NULL, PMSort, (void*)LeftArg);
pthread_create(&RThread, NULL, PMSort, (void*)RightArg);
pthread_join(LThread, NULL);
pthread_join(RThread, NULL);
Merge(A, p, q, r);
}
}
}
void Merge(float A[], int p, int q, int r){
int n1 = q -p + 1;
int n2 = r - q;
int i = 0;
int j = 0;
int L[r];
int R[r];
for (i = 0; i < n1; i ++){
L[i] = A[p + i];
}
for (j = 0; j < n2; j ++){
R[j] = A[q + j + 1];
}
L[n1] = INFINITY;
L[n2] = INFINITY;
i = 0;
j = 0;
for (int k = p; k <= r; k ++){
if (L[i] <= R[j]){
A[k] = L[i];
i ++;
}
else {
A[k] = R[j];
j ++;
}
}
}
void MergeSort(float A[], int p, int r){
int q;
if (p < r){
q = (p + r)/2;
MergeSort(A, p, q);
MergeSort(A, p+1, r);
Merge(A, p, q, r);
}
}
int main(void){
float array[] = {5,2,4,7,1,3,2,6};
ParallelMergeSort(array, 0, 7, 0, 3);
for (int i = 0; i <= 7; i ++){
printf("%f ", array[i]);
}
printf("\n");
return 0;
}
Don't ignore return values from function calls in C. Start out by adding perror calls if your pthread calls do not return 0 and see what happens. You will see that the pthread_join calls are failing because you have RThread and LThread declared as globals. So you keep re-assigning them new values as you spawn off threads. Move those pthread_t declarations so they are declared inside the ParallelMergeSort function instead.
That won't fix any sorting issues with your algorithm but at least you will get consistent results.