C Parallel merge sort working sometimes - c

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(&LThread, 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.

Related

Seg Fault calling mergesort on pointer array

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);
}
}

Quick Sort Array Random Number Generator Nothing Printed Error

I have this C code that creates an array with 100 random numbers and I want to sort it using quick sort, but it always gives a Segmentation fault error.
Here is the code:
#define MAX 100
int a[MAX];
void quick_sort(double *x, int l, int r) {
int l1, r1;
if (l < r) {
l1 = l;
r1 = r;
do {
while (l1 < r && x[l1 - 1] <= x[l - 1]) {
l1++;
}
while (l < r1 && x[r1 - 1] >= x[l - 1]) {
r1--;
}
if (l1 < r1) {
swap(&x[l1 - l], &x[r1 - 1]);
}
} while (l1 < r1);
swap(&x[l - 1], &x[r1 - 1]);
quick_sort(x, l, r1 - 1);
quick_sort(x, r1 + 1, r);
}
}
void printArray(int a[], int size) {
int i;
for (i = 0; i < size; i++)
printf("%d ", a[i]);
printf("\n");
}
int main() {
int i = 1;
int a_size = sizeof(a) / sizeof(a[0]);
srand((unsigned int)time(NULL));
for (i = 0; i < MAX; i++) {
a[i] = rand() % 501;
}
quick_sort(a, 0, a_size);
printArray(a, a_size);
}
The error is that nothing prints when I run the program.
Can someone help me with the problem?
There are many problems in your code:
You do not include <stdio.h>, <stdlib.h>, nor <time.h>.
Your quick_sort function expects a pointer to an array of double, yet you pass an array of int.
The code for function swap() is not posted.
Your implementation of the Quick Sort algorithm in function quick_sort is flawed:
you should not scan slices of size 1, use (r - l > 1).
You cannot use x[l - 1] as pivot, it is not even part of the slice to be sorted. Furthermore, you should extract the pivot from the array before the swapping phase as it may move.
You should not name a variable l, it looks too close to 1 and you do make the mistake here: swap(&x[l1 - l], &x[r1 - 1]);
You should initialize l1 and r1 such that you do not need to subtract 1 in so many places, it leads to confusion and erroneous code.
Study the algorithms from the Wikipedia article and translate one to C.
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 100
void swap(int *a, int *b) {
int x = *a;
*a = *b;
*b = x;
}
// Quick Sort using Hoare's original partition scheme
void quick_sort(int *x, int l, int r) {
if (l < r) {
int pivot = x[l];
int l1 = l - 1;
int r1 = r;
for (;;) {
while (x[++l1] < pivot)
continue;
while (x[--r1] > pivot)
continue;
if (l1 < r1) {
swap(&x[l1], &x[r1]);
} else {
break;
}
}
quick_sort(x, l, r1 + 1);
quick_sort(x, r1 + 1, r);
}
}
void printArray(int a[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int main(void) {
int a[MAX];
int a_size = sizeof(a) / sizeof(a[0]);
srand((unsigned int)time(NULL));
for (int i = 0; i < MAX; i++) {
a[i] = rand() % 501;
}
quick_sort(a, 0, a_size);
printArray(a, a_size);
return 0;
}

QuickSort Algorithm Number of Comparisons

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.

Quicksort not working well

I have tried to implement a quicksort using a pseudo-code from a book(looks like the one from wikipedia), but I can't get it to make it work.
This source code:
int partitionare(int a[], int n, int p, int r)
{
int x, i, j, aux;
x = a[r]; // pivot
i = p - 1;
for (j = p; j < r; j++)
{
if (a[j] <= x)
{
i++;
aux = a[j];
a[j] = a[i];
a[i] = aux;
}
}
aux = a[i + 1];
a[i + 1] = a[r];
a[r] = aux;
return i + 1;
}
void quicksort(int a[], int n, int p, int r)
{
if (p < r)
{
int q = partitionare(a, n, p, r);
partitionare(a, n, p, q - 1);
partitionare(a, n, q + 1, r);
}
}
where p and r are the beggining and the end of the array
And the call function:
quicksort(a, n, 0, n-1);
Don't mind that second argument, n. That is just for testing purpose only.
Accoding to the Wikipedia article the last calls inside the function quicksort() are to itself recursively (not to the function partition())
void quicksort(int a[], int n, int p, int r)
{
if (p < r)
{
int q = partitionare(a, n, p, r);
partitionare(a, n, p, q - 1); /* recursive quicksort() here */
partitionare(a, n, q + 1, r); /* recursive quicksort() here */
}
}

Mergesort gives garbage value for the first element of the sorted array when executing

I am implementing Mergesort using the algorithm described in "Introduction to Algorithms". However, upon every execution I get a garbage value as the first element of the sorted array. Here is the code for it:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void mergesort(int a[], int p, int r);
void merge(int a[], int p, int q, int r)
{
int *left, *right;
int i,j,k,l,n1,n2;
n1 = q-p+1;
n2 = r-q;
left = malloc(sizeof(int)*(n1+1));
right = malloc(sizeof(int)*(n2+1));
for ( i = 0; i < n1; i++) {
left[i] = a[p+i];
}
for ( j = 0; j < n2; j++) {
right[j] = a[q+j+1];
}
left[n1] = INT_MAX;
right[n2] = INT_MAX;
i = 0;
j = 0;
for ( k = p; k <= r; k++) {
if (left[i] <= right[j]) {
a[k] = left[i];
i++;
}
else {
a[k] = right[j];
j++;
}
}
free(left);
free(right);
return ;
}
int main(int argc, char* argv[])
{
int i;
int a[] = {5,2,4,7,1,3,2,6} ;
mergesort(a,0,sizeof(a)/sizeof(int));
for ( i = 0; i < sizeof(a)/sizeof(int); i++) {
printf("%d\n",a[i]);
}
return 0;
}
void mergesort(int a[], int p, int r)
{
if (p < r) {
int q;
q = (p+r)/2 ;
mergesort(a,p,q);
mergesort(a,q+1,r);
merge(a,p,q,r);
}
}
It looks like you have not clearly defined the meanings of the mergesort parameters. Here, your last element is positioned one past the end of the array:
mergesort(a,0,sizeof(a)/sizeof(int));
But here,
mergesort(a,p,q);
mergesort(a,q+1,r);
Q seems to be over the last element in the array. If your code follows the first, you will be forgetting to actually sort the value q. If it follows the second, you will be attempting to sort a garbage value one past the end of the array.
Shouldn't
mergesort(a,0,sizeof(a)/sizeof(int));
be
mergesort(a,0,sizeof(a)/sizeof(int)-1);
?
Considering you do
n1 = q-p+1;
etc.
There is almost certainly an off-by-one error somewhere in here.
You must chose if you want to include a[r] or not. Here your choice is not consistent hence the error.
Here is a good code (I don't include a[r]):
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void mergesort(int a[], int p, int r);
void merge(int a[], int p, int q, int r)
{
int *left, *right;
int i,j,k,l,n1,n2;
n1 = q-p;
n2 = r-q;
left = malloc(sizeof(int)*(n1+1));
right = malloc(sizeof(int)*(n2+1));
for ( i = 0; i < n1; i++) {
left[i] = a[p+i];
}
for ( j = 0; j < n2; j++) {
right[j] = a[q+j];
}
left[n1] = INT_MAX;
right[n2] = INT_MAX;
i = 0;
j = 0;
for ( k = p; k < r; k++) {
if (left[i] <= right[j]) {
a[k] = left[i];
i++;
}
else {
a[k] = right[j];
j++;
}
}
free(left);
free(right);
return ;
}
int main(int argc, char* argv[])
{
int i;
int a[] = {5,2,4,7,1,3,2,6} ;
mergesort(a,0,sizeof(a)/sizeof(int));
for ( i = 0; i < sizeof(a)/sizeof(int); i++) {
printf("%d\n",a[i]);
}
return 0;
}
void mergesort(int a[], int p, int r)
{
if (r-p > 1) {
int q;
q = (p+r)/2 ;
mergesort(a,p,q);
mergesort(a,q,r);
merge(a,p,q,r);
}
}

Resources