-
Notifications
You must be signed in to change notification settings - Fork 0
/
lift_sim_A.c
232 lines (187 loc) · 7.95 KB
/
lift_sim_A.c
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
* Copyright (c) 2020 Rohan Khayech
*/
/* Lift Sim A C File*/
/* Implementation of the main functions for Part A using threads. */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "lift_sim.h"
#include "log.h"
#include "lift_sim_A.h"
/* Shared variables */
int numItems; /* The current amount of requests stored in the buffer. */
int maxBuffSize; /* The maximum amount of requests that the buffer can store. */
int requestTime; /* The time in seconds that a lift takes to perform a request. */
int end; /* Boolean indicating whether there are any requests left to read (if not the program can end once requests have been processed). */
pthread_mutex_t bufferLock; /* Mutex lock for accessing the buffer. */
pthread_cond_t fullCond; /* Condition variable. Threads will wait on this condition if the buffer is full. */
pthread_cond_t emptyCond; /* Condition variable. Threads will wait on this condition if the buffer is empty. */
LiftRequest **buffer; /* Buffer used to store the lift requests. Dynamic array of LiftRequest pointers. */
int in; /* 'Pointer' to the next free space in the buffer. */
int out; /* 'Pointer' to the next filled space in the buffer. */
/* The main line for Part A */
int main(int argc, char **argv)
{
pthread_t liftR; /* The Lift Request thread. */
pthread_t lift1, lift2, lift3; /* A lift thread. */
Lift *l1, *l2, *l3; /* Pointer to a lift struct holding data about the lift. */
if (argc == 3 && atoi(argv[1]) >= 1 && atoi(argv[2]) >= 0) /* if command args are correct */
{
/* init end value to 0 */
end = 0;
/* read the command args */
maxBuffSize = atoi(argv[1]);
requestTime = atoi(argv[2]);
/* allocate the buffer array */
buffer = (LiftRequest**)calloc(maxBuffSize, sizeof(LiftRequest*));
/* init the buffer 'pointers' and counter */
in = 0;
out = 0;
numItems = 0;
/* allocate 3 lift structs */
l1 = initLift();
l2 = initLift();
l3 = initLift();
/* init mutex locks */
pthread_mutex_init(&bufferLock, NULL);
pthread_mutex_init(&outputLock, NULL);
/* init condition variables for the buffer */
pthread_cond_init(&fullCond, NULL);
pthread_cond_init(&emptyCond, NULL);
/* empty the output log file */
clearLog();
/* create child threads */
pthread_create(&liftR, NULL, request, NULL);
pthread_create(&lift1, NULL, lift, (void*)l1);
pthread_create(&lift2, NULL, lift, (void*)l2);
pthread_create(&lift3, NULL, lift, (void*)l3);
/* join and wait for all child threads to terminate */
pthread_join(liftR, NULL);
pthread_join(lift1, NULL);
pthread_join(lift2, NULL);
pthread_join(lift3, NULL);
/* free the buffer pointer */
free(buffer);
/* print out the total requests/movements to the log */
printTotals(l1,l2,l3);
/* free the lift pointers */
free(l1);
free(l2);
free(l3);
/* destroy mutex locks */
pthread_mutex_destroy(&bufferLock);
pthread_mutex_destroy(&outputLock);
/* destroy condition variables for the buffer */
pthread_cond_destroy(&fullCond);
pthread_cond_destroy(&emptyCond);
return 0;
}
else
{
/* prompt user to rerun program with the correct args */
printf("Usage: lift_sim_A m t\n");
printf("\tm = buffer size (must be >= 1)\n");
printf("\tt = request time (seconds)\n");
return 1; /* exit with error code 1 as the program couldn't run */
}
}
/* Lift Request Function */
/* Reads lift requests from the input file and places them in the shared buffer. */
void* request(void* ptr)
{
LiftRequest *r; /* Points to a lift request from the input file. */
FILE *sim_input; /* Pointer to the input file */
/*open the input file*/
sim_input = fopen("sim_input", "rb"); /* input file only accessed by the one process, doesn't require mutual exclusion */
if (sim_input != NULL) /* if the file opened correctly */
{
while (!end) /* while there are still requests to read */
{
/* retrieve a lift request from the input file if avaliable*/
r = readRequest(sim_input);
if (r != NULL) /* if the request is valid */
{
/* CRITICAL SECTION */
pthread_mutex_lock(&bufferLock); /* obtain lock for buffer */
while (numItems == maxBuffSize) /* wait if buffer is full*/
{
pthread_cond_wait(&fullCond, &bufferLock); /* wait until a consumer signals that the buffer is no longer full*/
}
/* place the lift request struct in the shared memory buffer */
buffer[in] = r;
/* print new request to console */
printf("New Lift Request from Floor %d to Floor %d\n",r->from,r->to);
printf("Request No: %d\n",r->rNum);
/* print new request to the log file */
printRequestToLog(r);
/* increase the in counter to the next free space in the buffer */
in = (in + 1) % maxBuffSize;
numItems++;
pthread_cond_broadcast(&emptyCond); /* signal to consumers that buffer is no longer empty*/
pthread_mutex_unlock(&bufferLock); /* release lock on buffer */
/* END CRITICAL SECTION */
}
else /* no more requests in file or request was invalid, terminate process*/
{
end = 1; /* liftR can terminate */
printf("No more requests in file. Ending LiftR.\n");
}
}
/*close the input file */
fclose(sim_input);
}
else
{
printf("Error opening file.\n");
end = 1; /* liftR can terminate */
}
return NULL;
}
/* Lift Operation Function */
/* Retrieves lift requests from the shared buffer and performs the specified operations. Takes a pointer to a Lift struct as an argument. (casted to a void pointer.) */
void *lift(void* ptr)
{
Lift* lift; /* The current lift. */
LiftRequest *r; /* Stores the lift request taken from the buffer */
int done = 0; /* Boolean indicating whether there are requests left to perform (if not the Lift thread will terminate) */
/* Cast and assign the lift pointer from the method argument */
lift = (Lift*)ptr;
/* take and perform request if avaliable or wait until avaliable */
while (done==0)
{
pthread_mutex_lock(&bufferLock); /* obtain lock on buffer */
/* CRITICAL SECTION */
while (numItems == 0) /* while buffer is empty */
{
if (end == 0)
{
pthread_cond_wait(&emptyCond, &bufferLock); /* wait until producer signals that the buffer is no longer empty */
}
else /*if no more requests in file or buffer*/
{
done = 1; /* lift can terminate */
pthread_mutex_unlock(&bufferLock);
break;
}
}
if(done==0) /* skip the operation code if no more requests to take */
{
/* retrieve the next request from the buffer, increase the out counter to the next place and decrease the numItems in the buffer */
r = buffer[out];
out = (out + 1) % maxBuffSize;
numItems--;
pthread_cond_broadcast(&fullCond); /* signal to producers that buffer is no longer full */
/* perform the lift operation */
moveLift(lift, r);
pthread_mutex_unlock(&bufferLock); /* release lock on buffer */
/* END CRITICAL SECTION */
/* free the request pointer */
free(r);
/* wait t seconds before retrieving another request */
sleep(requestTime);
}
}
return NULL;
}