Skip to content
Snippets Groups Projects
Commit becc5a9d authored by Brandon Rodriguez's avatar Brandon Rodriguez
Browse files

Implement handling of multiple threads to read multiple files

parent 823365ea
Branches
No related merge requests found
/**
* Brandon Rodriguez
* CS 3240
* 11-15-17
* a4 (Assignment 5)
*/
/**
* Description:
* Testing of thread implementation to solve a problem.
* Slightly more advanced example of joining with data passing.
*
* This reads in a provided directory and opens up threads equivalent to the number of
* files within. Each process handles a diffierent file, grabbing the first line,
* reading it, then returning the line to main which reads line again.
*/
/**
* Known Issues:
* No valgrind issues in small-data folder but valgrind finds four issues
* in large-data folder. Not sure where the errors are comming from, as valgrind
* (seemingly?) doesn't even point to any lines of code for this issue. Baffling.
*/
#define _BSD_SOURCE
// Import headers.
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "apue.h"
#include "HelperHeader.h"
// Define Vars.
#define BUFFER_SIZE 4096
// Variables.
typedef struct{
char* user_name;
char* password;
char* blood_type;
char* domain_name;
int db_index;
} data_struct;
int dir_file_counter;
char* absolute_path;
pthread_t* thread_array;
// Method Declaration.
int change_directory();
void open_folder();
void* thread_read_file(); // Reads given file and reorganizes data.
/**
* Program's main.
* Initializes and runs program.
*/
int main(int argc, char* argv[]) {
int index;
int return_int;
char* return_string;
// Check for valid args.
if (argc < 2) {
err_msg("Must enter a directory path.");
return -1;
} else if (argc > 2) {
err_msg("Must enter exacly one directory path.");
return -1;
} else {
return_int = change_directory(argv[1]);
if (return_int == 0) {
// Get absolute path.
absolute_path = calloc(BUFFER_SIZE, sizeof(char*));
if (getcwd(absolute_path, BUFFER_SIZE) == NULL) {
err_sys("Failed to get absolute path.");
}
// Open folder and create appropriate number of threads.
open_folder();
// Iterate through all threads and grab returned value.
for (index = 0; index < dir_file_counter; index++) {
pthread_join(thread_array[index], (void**) &return_string);
printf("Thread returned: %s", return_string);
free(return_string);
}
free(absolute_path);
free(thread_array);
}
}
return 0;
}
/**
* Safely changes directory by first checking path value and permissions.
*
* Returns 0 on success or -1 on failure.
*/
int change_directory(char* folder_location) {
int return_int;
struct stat stat_buffer;
return_int =lstat(folder_location, &stat_buffer);
if (return_int <0) {
err_sys("Failed to stat file with err %d", return_int);
return -1;
}
// First, ensure that it is, infact, a directory.
if (S_ISDIR(stat_buffer.st_mode)) {
// Next, check permissions.
if (access(folder_location, X_OK) == 0) {
// Change into directory.
return_int = chdir(folder_location);
if (return_int < 0) {
err_sys("Failed to change directory with err %d", return_int);
return -1;
}
} else { // No execute permission.
err_msg("No execute permission. Cannot change into directory.\n");
return -1;
}
} else { // Not a dir.
err_msg("Provided path is not a directory.\n");
return -1;
}
return 0;
}
/**
* Opens indicated folder and hands files off to threads.
*/
void open_folder() {
int index;
int return_int;
char* temp_string;
struct dirent* dir_struct;
struct stat stat_buffer;
DIR* dir_pointer;
// Iterate through directory first time, to count number of files to open/threads to make.
dir_file_counter = 0;
dir_pointer = opendir(absolute_path);
// Check that directory has read permissions.
if (access(absolute_path, R_OK) == 0) {
// Loop until no more files in directory.
while (dir_pointer != NULL) {
if ((dir_struct = readdir(dir_pointer)) != NULL) {
// New file found. Check if standard file type.
return_int = lstat(dir_struct->d_name, &stat_buffer);
if (return_int < 0) {
err_sys("Failed to stat file with err %d", return_int);
}
if (S_ISREG(stat_buffer.st_mode)) {
dir_file_counter++;
}
} else {
// End of files in directory. Closing stream.
return_int = closedir(dir_pointer);
if (return_int < 0) {
err_msg("Failed to properly close directory.");
}
dir_pointer = NULL;
}
}
} else {
err_msg("Directory does not have read access. Cannot view files.");
}
printf("Directory File Counter: %d\n", dir_file_counter);
// Prepare to set up threads.
thread_array = calloc(dir_file_counter, sizeof(pthread_t));
index = 0;
pthread_attr_t attr;
size_t stacksize;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize);
if (stacksize < 8388608) {
stacksize = 8388608;
}
pthread_attr_setstacksize(&attr, (stacksize * 2));
// Iterate through directory again. This time, actually create threads and hand off files.
dir_pointer = opendir(absolute_path);
// Check that directory has read permissions.
if (access(absolute_path, R_OK) == 0) {
// Loop until no more files in directory.
while (dir_pointer != NULL) {
if ((dir_struct = readdir(dir_pointer)) != NULL) {
// New file found. Check if standard file type.
return_int = lstat(dir_struct->d_name, &stat_buffer);
if (return_int < 0) {
err_sys("Failed to stat file with err %d", return_int);
}
if (S_ISREG(stat_buffer.st_mode)) {
// Get absolute file path.
temp_string = copy_string_with_buffer(absolute_path, BUFFER_SIZE);
strcat(temp_string, "/");
strcat(temp_string, dir_struct->d_name);
printf("Path: %s\n", temp_string);
// Actually create threads.
pthread_create(&thread_array[index], &attr, thread_read_file, (void*) copy_string(temp_string));
index++;
free(temp_string);
}
} else {
// End of files in directory. Closing stream.
return_int = closedir(dir_pointer);
if (return_int < 0) {
err_msg("Failed to properly close directory.");
}
dir_pointer = NULL;
}
}
} else {
err_msg("Directory does not have read access. Cannot view files.");
}
}
/**
* Uses thread to read file value.
*/
void* thread_read_file(void* file_location) {
FILE* read_file;
char* line_buffer = calloc(BUFFER_SIZE, sizeof(char*));
int result_int;
// printf("I'ma child and I was given dis: %s\n", file_location);
// pthread_exit(file_location);
read_file = fopen(file_location, "r");
fgets(line_buffer, BUFFER_SIZE, read_file);
free(file_location);
result_int = fclose(read_file);
if (result_int != 0) {
err_msg("Failed to close file properly.");
}
printf("I'ma child and I found dis: %s", line_buffer);
pthread_exit(line_buffer);
}
...@@ -27,14 +27,19 @@ ...@@ -27,14 +27,19 @@
*/ */
#define _BSD_SOURCE
// Import headers. // Import headers.
#include <ctype.h> #include <ctype.h>
#include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/stat.h>
#include "apue.h" #include "apue.h"
#include "HelperHeader.h"
// Define Vars. // Define Vars.
...@@ -49,10 +54,15 @@ typedef struct{ ...@@ -49,10 +54,15 @@ typedef struct{
char* domain_name; char* domain_name;
int db_index; int db_index;
} data_struct; } data_struct;
int dir_file_counter;
char* absolute_path;
pthread_t* thread_array;
// Method Declaration. // Method Declaration.
void* ThreadReadFile(); // Reads given file and reorganizes data. int change_directory();
void open_folder();
void* thread_read_file(); // Reads given file and reorganizes data.
/** /**
...@@ -60,34 +70,204 @@ void* ThreadReadFile(); // Reads given file and reorganizes data. ...@@ -60,34 +70,204 @@ void* ThreadReadFile(); // Reads given file and reorganizes data.
* Initializes and runs program. * Initializes and runs program.
*/ */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
pthread_t thread; int index;
int return_int;
char* file_location = "Data/small-data/0";
char* return_string; char* return_string;
pthread_create(&thread, NULL, ThreadReadFile, (void*) file_location); // Check for valid args.
pthread_join(thread, (void**) &return_string); if (argc < 2) {
printf("Thread returned:\n%s", return_string); err_msg("Must enter a directory path.");
free(return_string); return -1;
} else if (argc > 2) {
err_msg("Must enter exacly one directory path.");
return -1;
} else {
return_int = change_directory(argv[1]);
if (return_int == 0) {
// Get absolute path.
absolute_path = calloc(BUFFER_SIZE, sizeof(char*));
if (getcwd(absolute_path, BUFFER_SIZE) == NULL) {
err_sys("Failed to get absolute path.");
}
// Open folder and create appropriate number of threads.
open_folder();
// Iterate through all threads and grab returned value.
for (index = 0; index < dir_file_counter; index++) {
pthread_join(thread_array[index], (void**) &return_string);
printf("Thread returned: %s", return_string);
free(return_string);
}
free(absolute_path);
free(thread_array);
}
}
return 0;
}
/**
* Safely changes directory by first checking path value and permissions.
*
* Returns 0 on success or -1 on failure.
*/
int change_directory(char* folder_location) {
int return_int;
struct stat stat_buffer;
return_int =lstat(folder_location, &stat_buffer);
if (return_int <0) {
err_sys("Failed to stat file with err %d", return_int);
return -1;
}
// First, ensure that it is, infact, a directory.
if (S_ISDIR(stat_buffer.st_mode)) {
// Next, check permissions.
if (access(folder_location, X_OK) == 0) {
// Change into directory.
return_int = chdir(folder_location);
if (return_int < 0) {
err_sys("Failed to change directory with err %d", return_int);
return -1;
}
} else { // No execute permission.
err_msg("No execute permission. Cannot change into directory.\n");
return -1;
}
} else { // Not a dir.
err_msg("Provided path is not a directory.\n");
return -1;
}
return 0;
}
/**
* Opens indicated folder and hands files off to threads.
*/
void open_folder() {
int index;
int return_int;
char* temp_string;
struct dirent* dir_struct;
struct stat stat_buffer;
DIR* dir_pointer;
// Iterate through directory first time, to count number of files to open/threads to make.
dir_file_counter = 0;
dir_pointer = opendir(absolute_path);
// Check that directory has read permissions.
if (access(absolute_path, R_OK) == 0) {
// Loop until no more files in directory.
while (dir_pointer != NULL) {
if ((dir_struct = readdir(dir_pointer)) != NULL) {
// New file found. Check if standard file type.
return_int = lstat(dir_struct->d_name, &stat_buffer);
if (return_int < 0) {
err_sys("Failed to stat file with err %d", return_int);
}
if (S_ISREG(stat_buffer.st_mode)) {
dir_file_counter++;
}
} else {
// End of files in directory. Closing stream.
return_int = closedir(dir_pointer);
if (return_int < 0) {
err_msg("Failed to properly close directory.");
}
dir_pointer = NULL;
}
}
} else {
err_msg("Directory does not have read access. Cannot view files.");
}
printf("Directory File Counter: %d\n", dir_file_counter);
// Prepare to set up threads.
thread_array = calloc(dir_file_counter, sizeof(pthread_t));
index = 0;
pthread_attr_t attr;
size_t stacksize;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &stacksize);
if (stacksize < 8388608) {
stacksize = 8388608;
}
pthread_attr_setstacksize(&attr, (stacksize * 2));
// Iterate through directory again. This time, actually create threads and hand off files.
dir_pointer = opendir(absolute_path);
// Check that directory has read permissions.
if (access(absolute_path, R_OK) == 0) {
// Loop until no more files in directory.
while (dir_pointer != NULL) {
if ((dir_struct = readdir(dir_pointer)) != NULL) {
// New file found. Check if standard file type.
return_int = lstat(dir_struct->d_name, &stat_buffer);
if (return_int < 0) {
err_sys("Failed to stat file with err %d", return_int);
}
if (S_ISREG(stat_buffer.st_mode)) {
// Get absolute file path.
temp_string = copy_string_with_buffer(absolute_path, BUFFER_SIZE);
strcat(temp_string, "/");
strcat(temp_string, dir_struct->d_name);
printf("Path: %s\n", temp_string);
// Actually create threads.
pthread_create(&thread_array[index], &attr, thread_read_file, (void*) copy_string(temp_string));
index++;
free(temp_string);
}
} else {
// End of files in directory. Closing stream.
return_int = closedir(dir_pointer);
if (return_int < 0) {
err_msg("Failed to properly close directory.");
}
dir_pointer = NULL;
}
}
} else {
err_msg("Directory does not have read access. Cannot view files.");
}
} }
/** /**
* Uses thread to read file value. * Uses thread to read file value.
*/ */
void* ThreadReadFile(void* file_location) { void* thread_read_file(void* file_location) {
FILE* read_file; FILE* read_file;
char* line_buffer = calloc(BUFFER_SIZE, sizeof(char*)); char* line_buffer = calloc(BUFFER_SIZE, sizeof(char*));
int result_int; int result_int;
read_file = fopen(file_location, "r"); read_file = fopen(file_location, "r");
fgets(line_buffer, BUFFER_SIZE, read_file); fgets(line_buffer, BUFFER_SIZE, read_file);
free(file_location);
result_int = fclose(read_file); result_int = fclose(read_file);
if (result_int != 0) { if (result_int != 0) {
err_sys("Failed to close file properly."); err_msg("Failed to close file properly.");
} }
printf("I'ma child and I found dis: \n%s\n", line_buffer); printf("I'ma child and I found dis: %s", line_buffer);
pthread_exit(line_buffer); pthread_exit(line_buffer);
} }
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment