-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbakery_npn24.c
465 lines (398 loc) · 14.6 KB
/
bakery_npn24.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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
void random_sleep(double a, double b);
#define NUM_ITERATIONS 10
#define NUM_LEFT_OVEN_MITTS 3
#define NUM_RIGHT_OVEN_MITTS 3
//Helper function to sleep a random number of microseconds
//picked between two bounds (provided in seconds)
//pass 0.2 and 0.5 into this function as arguments
void random_sleep(double lbound_sec, double ubound_sec) {
int num_usec;
num_usec = lbound_sec*1000000 +
(int)((ubound_sec - lbound_sec)*1000000 * ((double)(rand()) / RAND_MAX));
usleep(num_usec);
return;
}
struct arguments{
pthread_mutex_t * right_lock;
pthread_mutex_t * left_lock;
pthread_mutex_t * mutex;
pthread_cond_t * right_availible;
pthread_cond_t * left_availible;
int * num_availible_right_mitts;
int * num_availible_left_mitts;
int num_batches;
int baker_type;
int baker_id;
int tid;
};
void *baker( void *arg );
void work( int type, int baker_id );
int getRightMitt( int type, int baker_id, int * num_availible_right_mitts,
pthread_mutex_t * right_lock, pthread_mutex_t * mutex, pthread_cond_t * right_availible );
int getLeftMitt( int type, int baker_id, int * num_availible_left_mitts,
pthread_mutex_t * left_lock, pthread_mutex_t * mutex, pthread_cond_t * left_availible );
int returnRightMitt(int type, int baker_id, int * num_availible_right_mitts,
pthread_mutex_t * right_lock, pthread_mutex_t * mutex, pthread_cond_t * right_availible);
int returnLeftMitt(int type, int baker_id, int * num_availible_left_mitts,
pthread_mutex_t * left_lock, pthread_mutex_t * mutex, pthread_cond_t * left_availible );
void bake(int type, int baker_id );
/*
* Main function
*/
int main(int argc, char **argv) {
int num_left_handed_bakers;
int num_right_handed_bakers;
int num_cautious_bakers;
int seed;
int num_availible_right_mitts = NUM_RIGHT_OVEN_MITTS;
int num_availible_left_mitts = NUM_LEFT_OVEN_MITTS;
pthread_mutex_t right_lock, left_lock, mutex;
pthread_mutex_init( &mutex, NULL );
pthread_mutex_init( &right_lock, NULL );
pthread_mutex_init( &left_lock, NULL );
pthread_cond_t right_availible;
pthread_cond_t left_availible;
pthread_cond_init( &right_availible, NULL );
pthread_cond_init( &left_availible, NULL );
/* Process command-line arguments */
if (argc != 5) {
fprintf(stderr,"Usage: %s <# left-handed bakers> <# right-handed bakers> <# cautious bakers> <seed>\n",argv[0]);
exit(1);
}
if ((sscanf(argv[1],"%d",&num_left_handed_bakers) != 1) ||
(sscanf(argv[2],"%d",&num_right_handed_bakers) != 1) ||
(sscanf(argv[3],"%d",&num_cautious_bakers) != 1) ||
(sscanf(argv[4],"%d",&seed) != 1) ||
(num_left_handed_bakers < 1) ||
(num_right_handed_bakers < 1) ||
(num_cautious_bakers < 1) ||
(seed < 0)) {
fprintf(stderr,"Invalid command-line arguments... Aborting\n");
exit(1);
}
/* Seed the RNG */
srand(seed);
// IMPLEMENT CODE HERE
int num_threads = num_left_handed_bakers + num_right_handed_bakers
+ num_cautious_bakers;
pthread_t worker_thread[ num_threads ];
struct arguments * args=(struct arguments *)malloc(sizeof(struct arguments)*num_threads);
int thread_index;
int left_baker_id = 0;
int right_baker_id = 0;
int cautious_baker_id = 0;
for( thread_index = 0; thread_index < num_threads; thread_index++ )
{
args[thread_index].right_lock= &right_lock;
args[thread_index].left_lock = &left_lock;
args[thread_index].mutex = &mutex;
args[thread_index].right_availible = &right_availible;
args[thread_index].left_availible = &left_availible;
args[thread_index].num_availible_right_mitts = &num_availible_right_mitts;
args[thread_index].num_availible_left_mitts = &num_availible_left_mitts;
args[thread_index].num_batches = 0;
args[thread_index].tid = thread_index;
// set baker's types where 1 = left handed, 2 = right handed, and 3 = cautious
if( thread_index < num_left_handed_bakers )
{
args[thread_index].baker_type = 1;
args[thread_index].baker_id = left_baker_id;
left_baker_id++;
}
else if( thread_index > num_left_handed_bakers &&
thread_index <= num_left_handed_bakers + num_right_handed_bakers)
{
args[thread_index].baker_type = 2;
args[thread_index].baker_id = right_baker_id;
right_baker_id++;
}
else
{
args[thread_index].baker_type = 3;
args[thread_index].baker_id = cautious_baker_id;
cautious_baker_id++;
}
if (pthread_create(&worker_thread[thread_index], NULL,
baker, (void *) &args[thread_index])) {
fprintf(stderr,"Error while creating thread #%d\n",thread_index);
exit(1);
}
}
// Joining with child threads
for (thread_index=0; thread_index < num_threads; thread_index++) {
if (pthread_join(worker_thread[thread_index], NULL)) {
fprintf(stderr,"Error while joining with child thread #%d\n",thread_index);
exit(1);
}
}
exit(0);
}
void *baker( void *arg )
{
// unpacking argument
struct arguments * myargs = (struct arguments*) arg;
int baker_type = myargs->baker_type;
int baker_id = myargs->baker_id;
int my_tid = myargs->tid;
int num_batches = myargs->num_batches;
int * num_availible_right_mitts = myargs->num_availible_right_mitts;
int * num_availible_left_mitts = myargs->num_availible_left_mitts;
pthread_mutex_t * right_lock = myargs->right_lock;
pthread_mutex_t * left_lock = myargs->left_lock;
pthread_mutex_t * mutex = myargs->mutex;
pthread_cond_t * right_availible = myargs->right_availible;
pthread_cond_t * left_availible = myargs->left_availible;
int has_right_mitt = 0;
int has_left_mitt = 0;
// loop while each thread hasn't done more than 10 batches of cookies
for( num_batches = 0; num_batches < 10; num_batches++ )
{
// each thread works
work( baker_type, baker_id );
// if the baker is left handed, get a left mitt and bake
if( baker_type == 1 )
{
has_left_mitt = getLeftMitt( baker_type, baker_id, num_availible_left_mitts + 1,
left_lock, mutex, left_availible );
if( has_left_mitt == 1 )
{
bake( baker_type, baker_id );
has_left_mitt = returnLeftMitt( baker_type, baker_id, num_availible_left_mitts + 1,
left_lock, mutex, left_availible );
}
}
// if the baker is right handed, get a right mitt and bake
if( baker_type == 2)
{
has_right_mitt = getRightMitt( baker_type, baker_id, num_availible_right_mitts + 1,
right_lock, mutex, right_availible );
if( has_right_mitt == 1 )
{
bake( baker_type, baker_id );
has_right_mitt = returnRightMitt( baker_type, baker_id, num_availible_right_mitts + 1,
right_lock, mutex, right_availible );
}
}
// if the baker is cautious, get both mitts and work
if(baker_type == 3)
{
has_left_mitt = getLeftMitt( baker_type, baker_id, num_availible_left_mitts + 1,
left_lock, mutex, left_availible );
has_right_mitt = getRightMitt( baker_type, baker_id, num_availible_right_mitts + 1,
right_lock, mutex, right_availible );
if( has_left_mitt == 1 && has_right_mitt == 1 )
{
bake( baker_type, baker_id );
has_left_mitt = returnLeftMitt( baker_type, baker_id, num_availible_left_mitts + 1,
left_lock, mutex, left_availible );
has_right_mitt = returnRightMitt( baker_type, baker_id, num_availible_right_mitts + 1,
right_lock, mutex, right_availible );
}
}
}
}
// funtion for bakers to work
void work( int type, int baker_id )
{
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] is working...\n", baker_id);
}
else if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] is working...\n", baker_id);
}
else
{
fprintf(stdout, "[Cautious baker %d] is working...\n", baker_id);
}
random_sleep( 0.2, 0.5 );
return;
}
// function for bakers to get a right mitt
int getRightMitt( int type, int baker_id, int * num_availible_right_mitts,
pthread_mutex_t * right_lock, pthread_mutex_t * mutex, pthread_cond_t * right_availible )
{
int ret_val = 0;
// this is where the bakers complain about what they want
if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] wants a right-handed mitt...\n", baker_id);
}
else
{
fprintf(stdout, "[Cautious baker %d] wants a right-handed mitt...\n", baker_id);
}
// set lock for accessing the number of availible right mitts
pthread_mutex_lock( right_lock );
// while there are no mitts to be gotten, tell the bakers to be patient until their
// mitt is availible
while( *num_availible_right_mitts <= 0 )
{
pthread_cond_wait( right_availible, right_lock );
}
// second lock for changing the number of availible right mitts
pthread_mutex_lock( mutex );
if( *num_availible_right_mitts > 0 )
{
// decrement the number of right mitts
*num_availible_right_mitts-=1;
ret_val = 1;
// allow the baker to tell the world that they finally got their precious mitt
if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] has got a right-handed mitt...\n", baker_id);
}
else if( type == 3)
{
fprintf(stdout, "[Cautious baker %d] has got a right-handed mitt...\n", baker_id);
}
// unlock inner lock
pthread_mutex_unlock( mutex );
}
// unlock outer lock
pthread_mutex_unlock( right_lock );
// return value indicating that this baker has his requested mitt
return ret_val;
}
// function for bakers to get a left mitt
int getLeftMitt( int type, int baker_id, int * num_availible_left_mitts,
pthread_mutex_t * left_lock, pthread_mutex_t * mutex, pthread_cond_t * left_availible )
{
int ret_val = 0;
// bakers complaining about how they need a left mitt
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] wants a left-handed mitt...\n", baker_id);
}
else
{
fprintf(stdout, "[Cautious baker %d] wants a left-handed mitt...\n", baker_id);
}
// lock the outer lock to access the number of availible left mitts
pthread_mutex_lock( left_lock );
// tell baker that they'll just have to wait if there are no left mitts
// availible. We only have so much money to spend on mitts.
while( *num_availible_left_mitts <= 0 )
{
pthread_cond_wait( left_availible, left_lock );
}
// lock the second lock to update the value of the number of left mitts and
// let the baker grab one.
pthread_mutex_lock( mutex );
if( *num_availible_left_mitts > 0 )
{
// decrement the number of left mitts
*num_availible_left_mitts-=1;
ret_val = 1;
// Reward the baker's patience with a chance to gloat to the other bakers
// about how they have a mitt and the others are still waiting.
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] has got a left-handed mitt...\n", baker_id);
}
else if( type == 3)
{
fprintf(stdout, "[Cautious baker %d] has got a left-handed mitt...\n", baker_id);
}
// unlock the inner lock
pthread_mutex_unlock( mutex );
}
// unlock the outer lock
pthread_mutex_unlock( left_lock );
// return the value indicating that this baker has a left mitt
return ret_val;
}
// function for bakers to return a right mitt
int returnRightMitt(int type, int baker_id, int * num_availible_right_mitts,
pthread_mutex_t * right_lock, pthread_mutex_t * mutex, pthread_cond_t * right_availible )
{
int ret_val = 1;
// lock to update the number of mitts
pthread_mutex_lock( right_lock );
// add one mitt to the availible right mitts
*num_availible_right_mitts+=1;
ret_val = 0;
// Give the baker the miracle of speech and let his coworkers know that a right
// mitt has been returned
if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] has put back a right-handed mitt...\n", baker_id);
}
else if( type == 3)
{
fprintf(stdout, "[Cautious baker %d] has put back a right-handed mitt...\n", baker_id);
}
// signal the other bakers waiting for a right mitt that it's time to act like
// it's black Friday and trample each other for a mitt
pthread_cond_signal( right_availible );
// unlock the lock
pthread_mutex_unlock( right_lock );
// return the value indicating that the baker no longer has a right mitt
return ret_val;
}
// function for bakers to return a left mitt
int returnLeftMitt(int type, int baker_id, int * num_availible_left_mitts,
pthread_mutex_t * left_lock, pthread_mutex_t * mutex, pthread_cond_t * left_availible )
{
int ret_val = 1;
// lock the lock to update the number of left mitts there are
pthread_mutex_lock( left_lock );
// put a mitt back
*num_availible_left_mitts+=1;
ret_val = 0;
// Have the baker scream out that he is (finally) done using a left mitt
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] has put back a left-handed mitt...\n", baker_id);
}
else if( type == 3)
{
fprintf(stdout, "[Cautious baker %d] has put back a left-handed mitt...\n", baker_id);
}
// signal the other bakers waiting (and definitely not complaining) that there
// is now a left mitt availible to the first person who can grab it
pthread_cond_signal( left_availible );
// unlock the lock
pthread_mutex_unlock( left_lock );
// return the value indicating that the baker no longer has a left mitt
return ret_val;
}
// function for bakers to bake
void bake(int type, int baker_id )
{
// Tell the baker to speak and tell everyone he is now baking
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] has put cookies in the oven and is waiting...\n", baker_id);
}
else if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] has put cookies in the oven and is waiting...\n", baker_id);
}
else
{
fprintf(stdout, "[Cautious baker %d] has put cookies in the oven and is waiting...\n", baker_id);
}
// put him to sleep because putting virtual cookies in an oven is very taxing
// on the virtual body
random_sleep( 0.2, 0.5 );
// Let the baker speak again and tell people he's done baking his cookies
if( type == 1 )
{
fprintf(stdout, "[Left-handed baker %d] has taken cookies out of the oven...\n", baker_id);
}
else if( type == 2 )
{
fprintf(stdout, "[Right-handed baker %d] has taken cookies out of the oven...\n", baker_id);
}
else
{
fprintf(stdout, "[Cautious baker %d] has taken cookies out of the oven...\n", baker_id);
}
return;
}