-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patha2main.c
More file actions
195 lines (159 loc) · 6.13 KB
/
a2main.c
File metadata and controls
195 lines (159 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Assignment 2 - CIS*3110
// Carter Rows - 1170615
// DUE DATE: March 27th @23:59
#include "cartersUtilities.h"
// hash table for all words found by all threads
TableWithMutex globalTable;
// count of completed threads
int completedThreads = 0;
pthread_mutex_t completedThreadsMutex;
// list of delimiters
char delimiters[] = ";.,/:;'()?!";
int main(int argc, char **argv) {
// variables for operation
int cmdOption = SUMMARY_TO_STDOUT;
// check for invalid command line arguments
if(argc > 2) {
// incorrect program usage
fprintf(stderr, "Invalid cmd args.\nUSAGE: ./A2checker [-l]\n\n");
exit(1);
}
// check for cmd line option -l
if(argc == 2) {
if(argv[1][0] == '-' && argv[1][1] == 'l') {
// valid cmd arg, update cmdOption variable
cmdOption = SUMMARY_TO_FILE;
} else {
fprintf(stderr, "Unrecognized option: '%s'\n", argv[1]);
exit(1);
}
}
// create the array for worker ids and arguments
pthread_t tid[MAX_WORKER_THREADS];
ThreadArgs args[MAX_WORKER_THREADS];
// create the message queue
MessageQueue *q = create_message_queue();
// create some attributes for the threads
pthread_attr_t attributes;
// initialize thread attributes.
pthread_attr_init(&attributes);
// make thread detached in the thread attributes
pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
// initialize our global table
globalTable.table = init_hash_table(HASH_TABLE_SIZE);
if(globalTable.table == NULL) {
fprintf(stderr, "Failed to allocate hash table for global.\n");
// clean up before exitting
free(q);
pthread_attr_destroy(&attributes);
exit(1);
}
// init mutex
pthread_mutex_init(&globalTable.mutex, NULL);
pthread_mutex_init(&completedThreadsMutex, NULL);
// now loop until user chooses exit
int userOption;
int threadCount = 0;
char dictionaryBuffer[MAX_FILENAME];
char inputFileBuffer[MAX_FILENAME];
while(1) {
// check for max threads
if(threadCount >= MAX_WORKER_THREADS) {
fprintf(stderr, "Max threads reached. Exitting.\n");
break;
}
// print main menu
display_menu();
scanf("%d", &userOption);
// check if we are starting new task or exitting
if(userOption == 1) {
// ask user for dictionary file
printf("\nEnter the dictionary file name, or type 'return' to go back to main menu:\t");
scanf("%64s", dictionaryBuffer);
if(!strncmp(dictionaryBuffer, "return", MAX_WORD_LEN)) {
// just skip the loop to go back to main menu
continue;
}
// do the same for input file name
printf("Enter the input file name, or type 'return' to go back to main menu:\t\t");
scanf("%64s", inputFileBuffer);
if(!strncmp(inputFileBuffer, "return", MAX_WORD_LEN)) {
// just skip the loop to go back to main menu
continue;
}
// check if we have valid file names
if(!is_valid_file(dictionaryBuffer)) {
fprintf(stderr, "Invalid file name: '%s'\n", dictionaryBuffer);
continue;
}
if(!is_valid_file(inputFileBuffer)) {
fprintf(stderr, "Invalid file name: '%s'\n", inputFileBuffer);
continue;
}
// if we are here, both input and dictionary file names are valid
// create a process to spellcheck
strncpy(args[threadCount].dictionaryFileName, dictionaryBuffer, MAX_WORD_LEN);
strncpy(args[threadCount].inputFileName, inputFileBuffer, MAX_WORD_LEN);
args[threadCount].q = q;
pthread_create(&tid[threadCount], &attributes, spell_checker_thread, &args[threadCount]);
// keep track of how many threads we have spawned
threadCount++;
}
else if(userOption == 2) {
// get out of the loop
break;
}
else {
fprintf(stderr, "Invalid choice. Please select either 1 or 2.\n");
}
}
// exitting logic here
int messagesRecieved = 0;
int totalMisspellings = 0;
// open the file pointer
FILE *outputFp = fopen("crows_A2.out", "w");
if(outputFp == NULL) {
fprintf(stderr, "Failed to open output file.\n");
// clean up before exitting
free(q);
delete_table(globalTable.table, HASH_TABLE_SIZE);
pthread_attr_destroy(&attributes);
exit(1);
}
// lock all mutexes now that we have exitted
pthread_mutex_lock(&completedThreadsMutex);
pthread_mutex_lock(&globalTable.mutex);
// check how many threads are finished / still running
int unfinishedThreads = threadCount - completedThreads;
if(unfinishedThreads > 0) {
printf("\n%d threads are still running.\n", unfinishedThreads);
} else {
printf("\nAll threads have completed their tasks.\n");
}
// get messages from threads
while(messagesRecieved < completedThreads) {
Message msg;
if(!get_message(q, &msg)) {
fprintf(stderr, "Failed to recieve message #%d\n", messagesRecieved);
}
// write the summary to output file
write_to_file(outputFp, msg.fileName, msg.totalIncorrect, &(msg.found));
totalMisspellings += msg.totalIncorrect;
messagesRecieved++;
}
// get stuff from global table
TopThree total;
find_top_three(globalTable.table, HASH_TABLE_SIZE, &total);
// now check the cmdOption to see if we put this info in the file or screen
if(cmdOption == SUMMARY_TO_STDOUT) {
print_summary(stdout, completedThreads, totalMisspellings, &total);
} else if(cmdOption == SUMMARY_TO_FILE) {
print_summary(outputFp, completedThreads, totalMisspellings, &total);
}
// free everything we dont need anymore
free(q);
delete_table(globalTable.table, HASH_TABLE_SIZE);
fclose(outputFp);
pthread_attr_destroy(&attributes);
exit(0);
}