CS431 - Homework #5
/********************************
Name: Thomas Heffron (tehqnf@umkc.edu)
Section: CS431 NET
Program: Program #5
Due Date: Nov. 19, 2002
Desc: Write a program that creates two
threads (using pthread_create) which
act as a producer and a consumer of
some virtual 'widget'. The main process
will take an alarm to end the threads
after a period of time.
Inputs: CMD argument given for duration of
main process - and associated threads.
Outputs: Timestamp showing beginning of main thread.
Threads will show each production/consumption.
Timestamp showing termination of main thread.
********************************/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
/* Buffer size changed here */
#define MAX_WIDGETS 20
/* Function declarations */
void *consume();
void *produce();
static void sig_alarm(int signo);
unsigned long get_time();
/* Global Variable declarations */
struct buffer_t {
int buffer[MAX_WIDGETS];
unsigned int nextFull;
unsigned int nextEmpty;
} widgets;
sem_t mutex, full, empty;
int stillrunning = 1;
struct timespec t;
int main(int argc, char *argv[])
{
/* Variable declarations */
int proc_duration, sem_ok, ret_val;
time_t now;
pthread_t pro_tid, con_tid;
/* Initializations of timer and pseudorandomizer */
t.tv_sec = 0;
srand(get_time() % 65000);
if (argc == 2) { /* Check for correct number of args */
proc_duration = atoi(argv[1]);
/* Set initial values on semaphores */
sem_ok = sem_init(&mutex, 0, 1);
sem_ok = sem_init(&full, 0, 0);
sem_ok = sem_init(&empty, 0, MAX_WIDGETS);
/* Start main thread */
time(&now);
printf("Thread creation started at %s", ctime(&now));
if (signal(SIGALRM, sig_alarm) == SIG_ERR) { /* define signal catch */
printf("The signal function returned an error\n");
exit(1);
}
printf("Setting alarm to end processes in %d seconds.\n\n",
proc_duration);
alarm(proc_duration); /* set alarm */
/* Create thread to produce widgets */
if ((pthread_create(&pro_tid, NULL, (void *) &produce, NULL)) > 0) {
printf("Couldn't create producer thread!\n");
exit(1);
} else { /* we are in main thread */
time(&now);
printf("Created producer with tid = %d at %s",
pro_tid, ctime(&now));
}
/* Create thread to consume widgets */
if ((pthread_create(&con_tid, NULL, (void *) &consume, NULL)) > 0) {
printf("Couldn't create consumer thread!\n");
exit(1);
} else { /* we are in main thread */
time(&now);
printf("Created consumer with tid = %d at %s",
con_tid, ctime(&now));
}
/* Now wait for threads to end */
/* Will be preempted by alarm signal */
pthread_join(pro_tid, NULL);
pthread_join(con_tid, NULL);
} else {
/* If not 2 arguments, then display usage */
printf("Usage: %s proc_duration\n", argv[0]);
exit(1);
}
}
static void sig_alarm(int signo)
{
time_t now;
alarm(0);
printf("\n*** Alarm to end process ***\n");
stillrunning = 0;
printf("Terminating threads...\n\n");
time(&now);
printf("Main process ending at %s\n", ctime(&now));
exit(0);
}
void *consume() {
/* Local variable declarations */
int con_num;
/* Continue to run until signaled from main */
while (stillrunning) {
sem_wait(&full); /* Dont try to consume
if buffer is empty */
sem_wait(&mutex); /* Wait for other threads
to exit critical section */
/* Read next item in buffer since last read */
/* Display results and increment to next buffer loc */
con_num = widgets.buffer[widgets.nextEmpty];
printf("Consuming widget #%2d in buffer space #%2d\n", con_num,
(widgets.nextEmpty + 1));
widgets.buffer[widgets.nextEmpty] = 0;
widgets.nextEmpty = (widgets.nextEmpty + 1) % MAX_WIDGETS;
/* Signal new buffer space and release locks */
sem_post(&empty);
sem_post(&mutex);
/* Sleep for a random number of microseconds */
t.tv_nsec = (1 + (int) (100.0*rand()/(RAND_MAX + 1.0))) * 10000000;
nanosleep(&t, NULL);
}
}
void *produce() {
/* Local variable declarations */
int prod_num = 1;
/* Continue to run until signaled by main */
while(stillrunning) {
sem_wait(&empty); /* Dont try to produce
if buffer is full */
sem_wait(&mutex); /* Wait for other threads
to exit critical section */
/* Display results of production, place in buffer
and increment counter to next location */
printf("Producing widget #%2d in buffer space #%2d\n", prod_num,
(widgets.nextFull + 1));
widgets.buffer[widgets.nextFull] = prod_num;
widgets.nextFull = (widgets.nextFull + 1) % MAX_WIDGETS;
prod_num++;
/* Signal new production and release locks */
sem_post(&full);
sem_post(&mutex);
/* Sleep for random number of microseconds */
t.tv_nsec = (1 + (int) (100.0*rand()/(RAND_MAX + 1.0))) * 10000000;
nanosleep(&t, NULL);
}
}
/* Simple routine to get a changing
number for seed of random number */
unsigned long get_time()
{
FILE *in_file;
unsigned long retval;
float trash;
in_file = fopen("/proc/uptime", "r");
fscanf(in_file, "%lu%f", &retval, &trash);
fclose(in_file);
return retval;
}