-
Brandon Rodriguez authored6fb31963
Main.c 8.09 KiB
/**
* Brandon Rodriguez
* CS 4540
* 02-27-18
* a4 (Assignment 4)
*/
/**
* Description:
*
* Args:
* First arg determines overall sleep time for the program.
* Main thread will directly use this arg as the sleep time, as long as it is greater than SLEEP_MIN.
* Subthreads' max sleep will be this arg modded by SLEEP_MAX. And no less than SLEEP_MIN.
* Second arg is number of producer threads to create.
* Third arg is number of consumer threads to create.
*
*
* Size of buffer is defined in buffer.h by BUFFER_SIZE.
* Currently set to 5 to (nearly gauranteed) test:
* Both multiple insertions and removals.
* Buffer case of all indexes full.
* Buffer case of all indexes empty.
*
*
* Program first creates consumer and producer threads, based on provided args.
* Once all threads are initialized, main sleeps based on args provided.
* When main wakes up, it terminates all threads and closes program.
*
*
* While main is sleeping, all threads enter loop of:
* * Initially sleep for random period of time between SLEEP_MIN and SLEEP_MAX
* (to ensure as much thread unpredictability as possible).
* * If producer, generate random number between 0 and 10,000.
* * Call (hopefully) thread-safe custom functions to access bounded buffer.
* * If producer, put generated number into lowest available buffer index.
* * If consumer, grab number from highest buffer index that is populated.
* * Return out of thread-safe functions and read out either value that was added or value that was taken
* (depending on if producer or consumer). If error occured, will be printed here.
*
*
* To make random numbers less random by using a constant seed on every run, comment out line #122 in main.
*/
/**
* Known Issues:
* Ran with:
* Varying min and max sleep times.
* Up to 100 second total run-time.
* Between 1 and 25 different consumers at once.
* Between 1 and 25 different producers at once.
* 1 consumer and 25 produers.
* 25 consumers and 1 producer.
*
* Seems to be no issues, as far as I can tell. Reads from and writes to buffer (seemingly) as intended.
*/
// Import headers.
#ifndef brodriguez_helper_functions
#define brodriguez_helper_functions
#include "brodriguez_helper_functions.h"
#endif
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include "buffer.h"
// Constant Defines.
#define SLEEP_MIN 2
#define SLEEP_MAX 10
// Variable Declaration.
int wait_on_main = 1;
// Method Declaration.
void* producer();
void* consumer();
/**
* Program's main.
* Initializes and runs program.
*/
int main(int argc, char* argv[]) {
int index;
int nap_length;
int producer_count;
int consumer_count;
int result_int;
int* max_time;
pthread_t* producer_array;
pthread_t* consumer_array;
// Ensure correct number of commands.
if (argc < 4) {
fprintf(stderr, "Too few arguments. Please provide sleep time, number of producers, and number of consumers.\n");
exit(1);
} else if (argc > 4) {
fprintf(stderr, "Too many arguments. Please provide sleep time, number of producers, and number of consumers.\n");
exit(1);
}
// Initialize values.
printf("Initializing...\n");
// Validate user input.
nap_length = atoi(argv[1]);
if (nap_length < SLEEP_MIN) {
fprintf(stderr, "Invalid sleep length. Must be a minimum of %d seconds.\n", SLEEP_MIN);
exit(1);
}
producer_count = atoi(argv[2]);
if (producer_count <= 0) {
fprintf(stderr, "Invalid number of producers. Must be greater than 0.\n");
exit(1);
}
consumer_count = atoi(argv[3]);
if (consumer_count <= 0) {
fprintf(stderr, "Invalid number of consumers. Must be greater than 0.\n");
exit(1);
}
max_time = calloc(1, sizeof(int));
*max_time = nap_length;
// Seeding random generator. Uncoment this for consistent seeding every program run.
srand(time(NULL));
intialize_item_buffer();
// Create producer thread(s).
printf("Creating producers...\n");
producer_array = calloc(producer_count, sizeof(pthread_t));
for (index = 0; index < producer_count; index++) {
printf("Main creating producer #%d.\n", index);
pthread_create(&producer_array[index], NULL, producer, (void*) max_time);
}
// Create consumer thread(s).
printf("Creating consumers...\n");
consumer_array = calloc(consumer_count, sizeof(pthread_t));
for (index = 0; index < consumer_count; index++) {
printf("Main creating consumer #%d.\n", index);
pthread_create(&consumer_array[index], NULL, consumer, (void*) max_time);
}
// Sleep main.
sleep(1);
printf("\nInitialization complete.\n");
printf("Main will now sleep for %d seconds.\n\n\n", nap_length);
wait_on_main = 0;
sleep(atoi(argv[1]));
printf("\n\n");
// Terminate program. First tell all threads to cancel.
for (index = 0; index < producer_count; index++) {
printf("Terminating producer #%d.\n", index);
result_int = pthread_cancel(producer_array[index]);
if (result_int < 0) {
fprintf(stderr, "Error terminating producer thread #%d.\n", index);
}
}
for (index = 0; index < consumer_count; index++) {
printf("Terminating consumer #%d.\n", index);
result_int = pthread_cancel(consumer_array[index]);
if (result_int < 0) {
fprintf(stderr, "Error terminating consumer thread #%d.\n", index);
}
}
// Then actually wait for threads to cancel. Producers first, then consumers.
for (index = 0; index < producer_count; index++) {
// printf("Joining producer thread #%d.\n", index);
pthread_join(producer_array[index], NULL);
printf("Joined producer thread #%d.\n", index);
}
for (index = 0; index < consumer_count; index++) {
// printf("Joining consumer thread #%d.\n", index);
pthread_join(consumer_array[index], NULL);
printf("Joined consumer thread #%d.\n", index);
}
free(max_time);
free(producer_array);
free(consumer_array);
exit(0);
}
/**
* Function for producer threads to run.
*/
void* producer(void* max_time) {
int sleep_actual;
int thread_sleep_max;
buffer_item item;
printf("Producer thread created.\n");
while(wait_on_main != 0) {
sleep(wait_on_main);
}
// Get random max for individual thread sleep. Max possible is SLEEP_MAX. Minimum is SLEEP_MIN.
thread_sleep_max = *(int*)max_time % SLEEP_MAX;
if (thread_sleep_max < SLEEP_MIN) {
thread_sleep_max = SLEEP_MAX;
}
// Loop until thread is terminated.
while(1) {
// Sleep thread for random time.
sleep_actual = rand() % thread_sleep_max;
// printf("Sleeping producer for %d seconds.\n", sleep_actual);
sleep(sleep_actual);
item = rand() % 10000;
if (insert_item(item) != 0) {
fprintf(stderr, "Producer failed to properly insert item %d.\n", item);
} else {
printf("Producer inserted item %d.\n", item);
}
}
return NULL;
}
/**
* Function for consumer threads to run.
*/
void* consumer(void* max_time) {
int sleep_actual;
int thread_sleep_max;
int* item;
printf("Consumer thread created.\n");
while(wait_on_main != 0) {
sleep(wait_on_main);
}
// Get random max for individual thread sleep. Max possible is SLEEP_MAX. Minimum is SLEEP_MIN.
thread_sleep_max = *(int*)max_time % SLEEP_MAX;
if (thread_sleep_max < SLEEP_MIN) {
thread_sleep_max = SLEEP_MAX;
}
// Loop until thread is terminated.
while(1) {
// Sleep thread for random time.
sleep_actual = rand() % thread_sleep_max;
// printf("Sleeping consumer for %d seconds.\n", sleep_actual);
sleep(sleep_actual);
item = calloc(1, sizeof(int));
if ((remove_item(item)) != 0) {
fprintf(stderr, "Consumer failed to properly remove item.\n");
} else {
printf("Consumer removed item with value %d.\n", *item);
}
free(item);
}
return NULL;
}