SICE Curriculum Portal for Thomas Heffron
Contents

Home
UMKC Curriculum
   FS '96
      CS 101
   SS '01
      CS 201
   FS '01
      CS 191
      CS 281
   WS '02
      CS 291
      EN 304wi
   SS '02
      CS 352
      CS 481
   FS '02
      CS 431
      CS 441
   WS '03
      CS 423
      CS 451
SICE Survival Guide
Personal Experience

contact me @umkc:
tehqnf@umkc.edu

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;
}