cis-452-lab-4/programming-assignment.c

172 lines
4.3 KiB
C
Raw Permalink Normal View History

2021-02-22 02:21:55 +00:00
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
/**************************************************************************
* Authors: Gary Fleming, Amber McCloughan
* Class: CIS452 - Operating Systems Concepts
* Professor: Dr. Greg Wolffe
* Date: 2/14/2019
*
* Program that starts out with a dispatcher thread. This thread
* waits on user input. When it receives a filename string from
* the user, it spawns a worker thread that goes out to
* "retrieve" the filename from the "file server". On an exit,
* the program prints statistics about files serviced.
*
* To end the program, do a Ctrl + C.
***************************************************************************/
// Input limit.
#define CHAR_LIMIT 1024
// See function implementations for information.
void *file_request(void *arg);
void sigHandler(int);
// File counter.
int counter;
// File access time counter.
int timeCounter;
// Mutex.
pthread_mutex_t lock;
// Input buffer.
char *input;
/**
* The main function for driving the program.
*/
int main()
{
// Seeding randomness.
srand(time(NULL));
/*
* Initializing the mutex.
* I figured out how to do this using the following article:
* https://www.geeksforgeeks.org/mutex-lock-for-linux-thread-synchronization/
*/
pthread_mutex_init(&lock, NULL);
// Thread ID holder.
pthread_t thread1;
// Status variable for checking if pthread_create failed.
int status;
// Initializing file counter.
counter = 0;
// Allocating memory for input buffer.
input = malloc(CHAR_LIMIT * sizeof(char));
// Binding signal handler for keyboard interrupt.
signal(SIGINT, sigHandler);
// The dispatching loop.
while (1)
{
// User input for filename.
fprintf(stderr, "Enter file name: ");
input = fgets(input, CHAR_LIMIT, stdin);
// Removing newline character from input.
strtok(input, "\n");
// Spawning a thread to deal with the "file" requested.
if ((status = pthread_create(&thread1, NULL, file_request, strdup(input))) != 0)
{
fprintf(stderr, "Thread creation error %d: %s.\n", status, strerror(status));
exit(1);
}
}
return 0;
}
/**
* Function executed by worked threads. Randomly decides
* whether the "file" can be accessed from the disk cache
* (80% chance) or if it has to be fetched from the hard
* drive (20% chance). If the "file" is accessed from cache,
* the thread sleeps for a second. If the "file" is accessed
* from the hard drive, the thread sleeps for 7-10 seconds.
* A mutex is used to ensure mutual exclusion for writes.
*
* @param arg, the name of the "file" to be handled by the
* worker thread.
*/
void *file_request(void *arg)
{
// Probability roll for HDD or cache.
int val = (rand() % 5) + 1;
// Variable used for sleep time.
int val2;
// File accessed from disk.
if (val == 5)
{
// 7-10 seconds.
val2 = (rand() % 4) + 7;
}
// File accessed from cache.
else
{
// 1 second.
val2 = 1;
}
// Sleep for seconds decided on above.
sleep(val2);
// Serving the file.
fprintf(stderr, "\nServing file \"%s\" after %i seconds.\n", (char *)arg, val2);
// Writing to global variables. Mutex lock!
pthread_mutex_lock(&lock);
counter++;
timeCounter += val2;
pthread_mutex_unlock(&lock);
// Freeing allocated memory.
free(arg);
// Goodbye (no need to return anything).
return NULL;
}
/**
* Handler for signals. Bound for the one signal handled
* in this application: SIGINT (program interrupt signal ^C).
*
* @param sigNum, the identifying number of the signal
* sent and now being handled. According to the
* man page for signal, SIGINT = 2.
*/
void sigHandler(int sigNum)
{
if (sigNum == SIGINT)
{
// Exit message.
printf(" received. That's it, I'm shutting you down...\n");
printf("Files serviced: %i.\n", counter);
printf("Avg. file access time: %lf seconds.\n", (double)timeCounter / (double)counter);
// Destroying mutex.
pthread_mutex_destroy(&lock);
// Freeing user input pointer.
free(input);
// Exiting program.
exit(0);
}
}