/**************************************************************** * * * CSC209h 200 Summer * * * * Assignment 4 * * * * Student Name: Jeff Xing * * Student Number: 990555323 * * Instructor: Arthur Tateishi * * * ****************************************************************/ /* This program simulates the daily work of a laundromat using POSIX threads APIs. It will display the number of customers served, the average loads per curstomer, the average and maximum time (in minutes) for a customer spend in the laundromat at the end of the simulation. To compile the program, use gcc -o simulaundry simulaundry.c -lpthread to run it, use ./simulaundry n where n is an integer which is not less than one. */ #include #include #include #define TOTAL_TIME 1440 /* 24x60=1440. */ #define NUM_MACHINES 15 /* number of washing machines. */ #define WASH_TIME 30 /* fixed washing time per load. */ #define MAX_LOAD 4 /* maximum load per customer. */ pthread_mutex_t mutex_th; /* global mutex variable. */ pthread_cond_t cond_th; /* global conditional variable. */ int count = 0; /* number of threads counted. */ /* interarrival time in minutes entered by user which is not less than one. */ int intArTime; /* random customer interarrival time between 0 to intArTime. */ int intArT; int nextAr; /* arrival time of next customer. */ int numCustServed = 0; /* total number of customers served. */ int numLoadTaken = 0; /* total number of loads served. */ int numCusAr = 0; /* total number of customers arrived. */ int numLoadAr = 0; /* total number of loads served. */ /* total waiting time of all customers served. */ int totalTime = 0; int maxWait = 0; /* maximum time of a customer spent. */ int curTime = 0; /* the clock start from zero. */ int queue_head = 0; /* the head of the customer queue. */ int queue_end = 0; /* the end of the customer queue. */ /* array to store all arrival customers information: cloumn zero is * arrival time, column one is loads of that customer. */ int cust_load[2*TOTAL_TIME][2]; /************************************************************************ * threads created by simulate function, each thread works as a washing * * machine: taking a load from a customer (if there is one) and doing its* * job, counting the number of loads, customers served and adding to * * the approprate global variables until the end of the day. */ void * processWM() { int finishT; /* The time that I'll finish my work. */ finishT = WASH_TIME; nextAr = rand() % (intArTime + 1); /* initialize the next arrival*/ /* Do my work until the end of the day (24 hours). */ while (curTime < TOTAL_TIME) { pthread_mutex_lock(&mutex_th); if (count < NUM_MACHINES - 1) /* Do my job. */ { count++; /* wait for my turn. */ pthread_cond_wait(&cond_th, &mutex_th); if (nextAr == curTime && curTime < TOTAL_TIME - 30) /* generate a new customer. */ { cust_load[queue_end][0] = curTime; cust_load[queue_end][1] = rand() % MAX_LOAD + 1; numLoadAr += cust_load[queue_end][1]; numCusAr++; intArT = rand() % (intArTime + 1); queue_end++; if (intArT == 0) { cust_load[queue_end][0] = curTime; cust_load[queue_end][1] = rand() % MAX_LOAD + 1; numLoadAr += cust_load[queue_end][1]; numCusAr++; queue_end++; intArT = rand() % intArTime; } /* remember the time to generate next customer. */ nextAr = curTime + intArT; } if (finishT <= curTime && queue_end > queue_head) /* I finished my current job and will take next order (if there is one). */ { cust_load[queue_head][1]--; numLoadTaken ++; if (cust_load[queue_head][1] == 0) /* dequeue the customer */ { totalTime += (curTime - cust_load[queue_head][0]) + 30; queue_head++; numCustServed++; if ((curTime - cust_load[queue_head][0]) + 30 > maxWait) /* reset the maximum spending time. */ maxWait = (curTime - cust_load[queue_head][0]) + 30; } /* remember my finishing time. */ finishT = curTime + WASH_TIME; } } else /* all threads finished their turn, increase time by one, reset count and broadcast. */ { curTime++; count = 0; pthread_cond_broadcast(&cond_th); } pthread_mutex_unlock(&mutex_th); } pthread_exit(NULL); } /******************************************************************** create the threads to do their job, destroy them and print out the simulating results upon completion. */ void simulate() { float avg_load; float avg_wait; int i, status; pthread_t thread[NUM_MACHINES]; pthread_attr_t attr; /* initialize mutex and conditional variables. */ status = pthread_mutex_init(&mutex_th, NULL); if (status != 0) { fprintf(stderr, "mutex_th init error: %s\n", strerror(status)); return; } status = pthread_cond_init(&cond_th, NULL); if (status != 0) { fprintf(stderr, "cond_th init error: %s\n", strerror(status)); return; } /* Initialize pthread attribute object */ pthread_attr_init(&attr); /* set attribute so that threads are created as system scheduled threads*/ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); for (i=0; i < NUM_MACHINES ; i++) { status = pthread_create(&thread[i], &attr, (void *)processWM, (void*)i); if (status != 0) { fprintf(stderr, "Creation error on thread %d: %s\n", i, strerror(status)); } } /* create the threads I needed. */ for (i = 0; i < NUM_MACHINES ; i++) { status = pthread_join(thread[i], NULL); if (status != 0) fprintf(stderr, "Join error on thread %d: %s\n", i, strerror(status)); } /* destroy the mutex and conditional variables. */ status = pthread_mutex_destroy(&mutex_th); if(status != 0) fprintf(stderr, "mutex_th destroy error: %s\n", strerror(status)); status = pthread_cond_destroy(&cond_th); if(status != 0) fprintf(stderr, "cond_th destroy error: %s\n", strerror(status)); /* calculate and display the data needed. */ avg_load = (float)numLoadTaken / numCustServed; avg_wait = (float)totalTime / numCustServed; fprintf(stdout, "number of customers arrived: %d\n", numCusAr); fprintf(stdout, "number of loads arrived: %d\n\n", numLoadAr); fprintf(stdout, "number of customers served: %d\n", numCustServed); fprintf(stdout, "average load per customer: %g\n", avg_load); fprintf(stdout, "average spending time per served customer: %g minutes.\n", avg_wait); fprintf(stdout, "maximum spending time of a customer: %d minutes.\n", maxWait); pthread_exit(NULL); /* Just for safety. */ } /****************************************************************** * the main function parses and checks the commands, call simulate() * and exit upon the finish. */ int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "USUAGE: simulaundry interarrical-time\n"); exit(1); } intArTime = atoi(argv[1]); if (intArTime < 1) { fprintf(stderr, "invalid interarrival time: must be an integer and not less than one\n"); exit(1); } simulate(); return 0; }