- /*
- * Machine Problem #3
- * CS 241, Spring 2011
- *
- * Implements parallel file-based mergesort
- * Uses qsort library for per file sort
- */
- #include <stdio.h> /* Standard buffered input/output */
- #include <stdlib.h> /* Standard library functions */
- #include <string.h> /* String operations */
- #include <pthread.h> /* Thread related functions */
- //passed into threads
- typedef struct _input_args{
- char *file;
- FILE *output;
- } input_args_t;
- typedef struct _input_files{
- FILE *file1;
- FILE *file2;
- FILE *t_file;
- } input_files_t;
- //int compare for qsort
- int int_compare(const void *a, const void *b){
- return *(int*) a - *(int*) b;
- }
- //counts numbers in file
- int num_count(FILE *input){
- int i=0;
- char c;
- rewind(input);
- c = fgetc(input);
- while(c != EOF){
- if(c == '\n')
- i++;
- c = fgetc(input);
- }
- rewind(input);
- return i;
- }
- //sorts files and writes new "input.sorted" files as output
- void *file_sort(void* args){
- int i=0, count=0;
- char input_read[12];
- char i_name[100], o_name[100];
- //assign file names to i_name and o_name
- strcpy(i_name, ((input_args_t*)args)->file);
- *o_name = '\0';
- strcat(o_name,((input_args_t*)args)->file);
- strcat(o_name,".sorted");
- //create file descriptors
- FILE *input = fopen(i_name,"r");
- FILE *output = ((input_args_t*)args)->output;
- //count the numbers in the file and create an array of that size
- count = num_count(input);
- int input_num[count];
- //get strings and read into the integer array
- while(fgets(input_read,11,input) != NULL){
- input_num[i] = atoi(input_read);
- i++;
- }
- //sort and print array into ".sorted" file
- qsort(input_num,count,sizeof(int),int_compare);
- for(i=0;i<count;i++)
- fprintf(output, "%d\n", input_num[i]);
- printf("This worker thread writes %d lines to \"%s\".\n", count, o_name);
- fclose(input);
- return NULL;
- }
- //merge two files into a temp file
- void *file_merge(void *files){
- int i=0,j=0,k=0,x=0,count1 = 0,count2 = 0,count3 = 0;
- char input_read[12];
- //create file descriptors
- FILE *input1 = ((input_files_t*)files)->file1;
- FILE *input2 = ((input_files_t*)files)->file2;
- FILE *output = ((input_files_t*)files)->t_file;
- //count the numbers in the file and create arrays of corresponding size
- count1 = num_count(input1);
- count2 = num_count(input2);
- count3 = count1 + count2;
- int input_num1[count1];
- int input_num2[count2];
- int output_num[count3];
- //get strings and read into the integer array
- while(fgets(input_read,11,input1) != NULL){
- input_num1[i] = atoi(input_read);
- i++;
- }
- while(fgets(input_read,11,input2) != NULL){
- input_num2[j] = atoi(input_read);
- j++;
- }
- //merge input_num1 and input_num2 into output_num
- i=0;
- j=0;
- while(i < count1 && j < count2){
- if(input_num1[i] == input_num2[j]){
- j++;
- count3--;
- }
- else if(input_num1[i] < input_num2[j]){
- output_num[k] = input_num1[i];
- i++;
- k++;
- }
- else{
- output_num[k] = input_num2[j];
- j++;
- k++;
- }
- }
- if(i < count1){
- for(x=i; x < count1; x++){
- output_num[k] = input_num1[x];
- k++;
- }
- }
- else{
- for(x=j; x < count2; x++){
- output_num[k] = input_num2[x];
- k++;
- }
- }
- //print output_num to output (t_file)
- for(i=0;i<count3;i++){
- printf("%d\n", output_num[i]);
- fprintf(output, "%d\n", output_num[i]);
- }
- printf("Merged %d lines and %d lines into %d lines.\n", count1, count2, count3);
- return NULL;
- }
- /* MAIN PROCEDURE SECTION */
- int main(int argc, char **argv){
- int i=0, num_files = argc - 1;
- char o_name[100];
- pthread_t *thread = malloc(num_files*sizeof(pthread_t));
- input_args_t *args = malloc(num_files*sizeof(input_args_t));
- input_files_t *files1= malloc((num_files/2+1)*sizeof(input_files_t));
- input_files_t *files2= malloc((num_files/2+1)*sizeof(input_files_t));
- //create individual sorted output files and call file_sort()
- for(i=0;i < num_files; i++){
- args[i].file = argv[i+1];
- *o_name = '\0';
- strcat(o_name, args[i].file);
- strcat(o_name,".sorted");
- args[i].output = fopen(o_name, "w+");
- pthread_create(&thread[i],NULL,file_sort,&args[i]);
- }
- for(i=0;i < num_files; i++)
- pthread_join (thread[i],NULL);
- //put output in args structs into files structs
- for(i=0;i < num_files/2;i++){
- printf("struct switch is run and i is %d\n", i);
- rewind(args[i*2].output);
- files1[i].file1 = args[i*2].output;
- rewind(args[i*2+1].output);
- files1[i].file2 = args[i*2+1].output;
- files1[i].t_file = tmpfile();
- }
- if(num_files % 2 == 1){
- i++;
- rewind(args[i*2].output);
- files1[i].t_file = args[i*2].output;
- }
- //merge the temp files
- int num_threads = i;
- printf("num_threads: %d\n", num_threads);
- for(i=0;i < num_threads;i++)
- pthread_create(&thread[i],NULL,file_merge,&files1[i]);
- for(i=0;i < num_files; i++)
- pthread_join(thread[i],NULL);
- //continue merging temp files until 1 temp file is left
- while(num_threads > 1){
- for(i=0;i < num_threads/2;i++){
- rewind(files1[i*2].t_file);
- files2[i].file1 = files1[i*2].t_file;
- rewind(files1[i*2+1].t_file);
- files2[i].file2 = files1[i*2+1].t_file;
- files2[i].t_file = tmpfile();
- }
- if(num_threads % 2 == 1){
- i++;
- rewind(args[i*2].output);
- files2[i].t_file = args[i*2].output;
- }
- num_threads = i;
- for(i=0;i < num_threads;i++){
- pthread_create(&thread[i],NULL,file_merge,&files2[i]);
- }
- for(i=0;i < num_files; i++)
- pthread_join(thread[i],NULL);
- for(i=0;i < num_threads;i++)
- files1[i].t_file = files2[i].t_file;
- }
- //when there is 1 temp file, write it to sorted.txt
- FILE *final_file = fopen("sorted.txt", "w");
- int num=0;
- while(fscanf(files1[0].t_file, "%d", &num) != EOF)
- fprintf(final_file, "%d\n", num);
- /*
- //close individually sorted files
- for(i=0;i < num_files; i++){
- fclose(args[i].output);
- }*/
- //free all memory
- free(thread);
- free(args);
- free(files1);
- free(files2);
- pthread_exit(NULL);
- return 0;
- } /* end main() */