diff options
Diffstat (limited to 'pgm5')
| -rw-r--r-- | pgm5/counter.c | 690 | ||||
| -rw-r--r-- | pgm5/makefile | 11 | ||||
| -rw-r--r-- | pgm5/p5test/file0 | 17 | ||||
| -rw-r--r-- | pgm5/p5test/file1 | 2 | ||||
| -rw-r--r-- | pgm5/p5test/file2 | 3 | ||||
| -rw-r--r-- | pgm5/p5test/file3 | 9 | ||||
| -rw-r--r-- | pgm5/p5test/file4 | 5 | ||||
| -rw-r--r-- | pgm5/p5test/file5 | 11 | ||||
| -rw-r--r-- | pgm5/p5test/file6 | 1 | ||||
| -rw-r--r-- | pgm5/prodcons.d/Makefile | 10 | ||||
| -rw-r--r-- | pgm5/prodcons.d/README | 2 | ||||
| -rw-r--r-- | pgm5/prodcons.d/prodcons.c | 124 | ||||
| -rw-r--r-- | pgm5/run.sh | 13 | 
13 files changed, 898 insertions, 0 deletions
| diff --git a/pgm5/counter.c b/pgm5/counter.c new file mode 100644 index 0000000..26735b4 --- /dev/null +++ b/pgm5/counter.c @@ -0,0 +1,690 @@ +/* + * counter.c + * Adam Carpenter - 2017 - acarpent - acarpenter@email.wm.edu + * Utilizes code from P. Kearns + * Utilizes code from linuxthreads demonstration "prodcons.c" + */ + + +// **** Library inclusions **** +#include<errno.h> +#include<pthread.h> +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<time.h> +#include<unistd.h> + + +// **** Definitions for counter **** +#define FALSE           0 +#define LEN_LINE        2048 +#define LEN_FILENAME    4096 +#define MAX_THREADS     26 +#define TRUE            1 +#define USAGE           "counter: usage: counter -b num_lines -t max_counters -d file_delay -D thread_delay [file]...\n" + + +// **** Structure declarations **** +struct prodConBuff { +    /* +     * struct prodConBuff +     */ +     pthread_mutex_t bufferLock;// Mutex ensures exclusive access to buffer. +     int readPos;               // Position for reading. +     int writePos;              // Position for writing. +     pthread_cond_t notEmpty;   // Signaled when buffer isn't empty. +     pthread_cond_t notFull;    // Signaled when buffer isn't full. +    //  char *lines[]; +     char **lines;             // Array of strings serves as data container. +}; + +struct NODE { +    /* +     * struct NODE +     */ +     char *word; // char *word or word[LEN_LINE] +     long count; +     struct NODE *next; +}; + +struct linkedList { +    /* +     * struct linkedList +     */ +     pthread_mutex_t listLock;  // Mutex ensures exclusive access to linked list. +     struct NODE *head;         // Pointer to first node in list. +}; + + +// **** Global variables **** +static char nextThread; +static int fileDelay; +static int maxCounters; +static int moreStuff; +static int numLines; +static int threadDelay; +static pthread_t threadPool[MAX_THREADS]; // Bad Threadpool. +struct prodConBuff buffer; +struct linkedList evenList; +struct linkedList oddList; + + +// **** Structure initializations **** +static void initBuffer(struct prodConBuff *buffer) { +    /* +     * initBuffer() initializes the buffer structure to an empty array ready for +     * producer-consumer actions. +     * The buffer of lines is initialized to NULL. As the program runs, if +     * slots are empty they will be malloc'd to fit given lines being inserted +     * into the buffer, and freed as they are taken out. +     */ +    int i; + +    pthread_mutex_init(&buffer->bufferLock, NULL); +    pthread_cond_init(&buffer->notEmpty, NULL); +    pthread_cond_init(&buffer->notFull, NULL); +    buffer->readPos = 0; +    buffer->writePos = 0; +    buffer->lines = (char **) calloc(numLines, LEN_LINE); + +    for (i = 0; i < numLines; i++) { +        buffer->lines[i] = (char *) calloc(LEN_LINE, sizeof(char)); +    } + +    if (numLines == 1) { +        buffer->lines[0][0] = '\0'; +    } +} + +static void initLinkedList(struct linkedList *list) { +    /* +     * initLinkedList() initializes the linked list structure (its lock and its +     * head node.) +     */ +    pthread_mutex_init(&list->listLock, NULL); +    list->head = NULL; +} + + +// **** Modifier and thread functions **** +static void sleeper(const struct timespec *req, struct timespec *rem) { +    // Researched methods of maintaining nanosleep times online and +    // found an interesting method using recursion that was similar to this. + +    struct timespec newRem; + +    if (nanosleep(req, rem) < 0) { +        sleeper(rem, &newRem); +    } + +} + +static void quitThread() { +    /* +     * quitThread() +     */ +    #ifdef atcdebug +    fprintf(stderr, "counter: thread quit because no more stuff.\n"); +    #endif + +    nextThread--; +    pthread_exit(NULL); +} + +static int putInBuffer(struct prodConBuff *buffer, char *line) { +    /* +     * putInBuffer() +     */ +    int newThread; + +    newThread = FALSE; +    pthread_mutex_lock(&buffer->bufferLock); + +    // If buffer is full, spawn a new counter thread. +    if ((buffer->writePos + 1) % numLines == buffer->readPos) { +        newThread = TRUE; +    } + +    // Wait until buffer isn't full anymore. +    while ((buffer->writePos + 1) % numLines == buffer->readPos) { +        pthread_cond_wait(&buffer->notFull, &buffer->bufferLock); + +        #ifdef atcdebug +        fprintf(stderr, "reader: waiting for space...\n"); +        #endif +    } + +    #ifdef atcdebug +    fprintf(stderr, "reader: gonna insert in slot: %d\n", buffer->writePos); +    #endif + +    // Copy the text into the next slot in the buffer. +    strncpy(buffer->lines[buffer->writePos], line, LEN_LINE); +    buffer->writePos++; + +    if (buffer->writePos >= numLines) { +        buffer->writePos = 0; +    } + +    #ifdef atcdebug +    fprintf(stderr, "reader: buffer is now: {  "); +    int i; +    for (i = 0; i < numLines; i++) { +        if (i == buffer->writePos) { +            fprintf(stderr, "*"); + +        } + +        fprintf(stderr, "%s  ", buffer->lines[i]); + +    } +    fprintf(stderr, "}\n\n"); +    #endif + +    // Signal buffer isn't empty anymore and unlock mutex. +    pthread_cond_signal(&buffer->notEmpty); +    pthread_mutex_unlock(&buffer->bufferLock); +    return newThread; +} + +static int putInSingleBuffer(struct prodConBuff *buffer, char *line) { +    /* +     * putInSingleBuffer(0) +     */ +    int newThread; + +    pthread_mutex_lock(&buffer->bufferLock); +    newThread = FALSE; + +    // If slot is taken, spawn a new counter thread +    if (buffer->lines[0][0] != '\0') { +        newThread = TRUE; +    } + +    // Wait until slot isn't full anymore. +    while (buffer->lines[0][0] != '\0') { +        pthread_cond_wait(&buffer->notFull, &buffer->bufferLock); +    } + +    // Insert line into buffer. +    strncpy(buffer->lines[buffer->writePos], line, LEN_LINE); + +    // Signal buffer slot isn't empty anymore and unlock mutex. +    pthread_cond_signal(&buffer->notEmpty); +    pthread_mutex_unlock(&buffer->bufferLock); +    return newThread; +} + +static void getFromBuffer(struct prodConBuff *buffer, char *line) { +    /* +     * getFromBuffer() +     */ + +    pthread_mutex_lock(&buffer->bufferLock); + +    // If buffer is 'empty' and nothing more will be written, quit. +    if (!moreStuff && buffer->readPos == buffer->writePos) { +        quitThread(); +    } + +    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + +    // Wait until buffer isn't empty anymore. +    while (buffer->readPos == buffer->writePos) { +        #ifdef atcdebug +        fprintf(stderr, "counter: waiting for stuff...\n"); +        #endif + +        pthread_cond_wait(&buffer->notEmpty, &buffer->bufferLock); +    } + +    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + +    #ifdef atcdebug +    fprintf(stderr, "counter: getting from slot: %d\n", buffer->readPos); +    #endif + +    // Get line from buffer and advance read position. +    strncpy(line, buffer->lines[buffer->readPos], LEN_LINE); +    buffer->readPos++; +    if (buffer->readPos >= numLines) buffer->readPos = 0; + +    #ifdef atcdebug +    fprintf(stderr, "counter: buffer is now: {  "); +    int i; +    for (i = 0; i < numLines; i++) { +        if (i == buffer->readPos) { +            fprintf(stderr, "*"); + +        } + +        fprintf(stderr, "%s  ", buffer->lines[i]); + +    } +    fprintf(stderr, "}\n\n"); +    #endif + +    // Signal buffer isn't full anymore and unlock mutex. +    pthread_cond_signal(&buffer->notFull); +    pthread_mutex_unlock(&buffer->bufferLock); +} + +static void getFromSingleBuffer(struct prodConBuff *buffer, char *line) { +    /* +     * getFromSingleBuffer(); +     */ + +    pthread_mutex_lock(&buffer->bufferLock); +    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + +    // Wait until buffer isn't empty anymore. +    while (buffer->lines[0][0] == '\0') { + +        // If buffer slot is empty and nothing more will be written to it, quit. +        if ((buffer->lines[0][0] == 0) && !moreStuff) { +            quitThread(); +        } + +        pthread_cond_wait(&buffer->notEmpty, &buffer->bufferLock); +    } + +    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + +    // Get line from buffer slot. +    strncpy(line, buffer->lines[0], LEN_LINE); +    buffer->lines[0][0] = '\0'; + +    // Signal buffer slot isn't full anmore and unlock mutex. +    pthread_cond_signal(&buffer->notFull); +    pthread_mutex_unlock(&buffer->bufferLock); +} + +static void putInList(struct linkedList *list, char *word) { +    /* +     * putInList() +     */ +    struct NODE *current; +    struct NODE *new; + +    pthread_mutex_lock(&list->listLock); + +    #ifdef atcdebug +    fprintf(stderr, "counter: gonna insert into list\n"); +    #endif + +    if (list->head == NULL) { +        new = (struct NODE *) malloc(sizeof(struct NODE)); +        new->word = (char *) malloc(strlen(word)); +        strcpy(new->word, word); +        new->count = 1; +        list->head = new; +    } +    else { + +        for (current = list->head; current != NULL; current = current->next) { + +            if (strcmp(current->word, word) == 0) { +                // Word already in list; update count. +                current->count++; +                break; +            } +            else if (current->next != NULL +                    && strcmp(word, current->next->word) < 0) { +                // Insert in front of next-greatest lexiographical word. +                new = (struct NODE *) malloc(sizeof(struct NODE)); +                new->word = (char *) malloc(strlen(word)); +                strcpy(new->word, word); +                new->count = 1; +                new->next = current->next; +                current->next = new; +                break; +            } +            else if (current->next == NULL) { +                // Reached the end; Insert at back of list. +                new = (struct NODE *) malloc(sizeof(struct NODE)); +                new->word = (char *) malloc(strlen(word)); +                strcpy(new->word, word); +                new->count = 1; +                new->next = NULL; +                current->next = new; +                break; +            } + +        } + +    } + +    #ifdef atcdebug +    fprintf(stderr, "counter: list is now: {"); +    current = list->head; +    while (current != NULL) { +        fprintf(stderr, "%s->", current->word); +        current = current->next; +    } +    fprintf(stderr, "}\n\n"); +    #endif + +    pthread_mutex_unlock(&list->listLock); +} + +static void printList(struct linkedList *list) { +    /* +     * printList() +     */ +     struct NODE *current; + +     // For debugging purposes and future implementations, lock the list. +     pthread_mutex_lock(&list->listLock); + +     // Print the word of every node in the list. +     for (current = list->head; current != NULL; current = current->next) { +         printf("Count: %ld Word: %s\n", current->count, current->word); +     } + +     pthread_mutex_unlock(&list->listLock); +} + +static void freeList(struct linkedList *list) { +    /* +     * freeList() +     */ +    struct NODE *current; +    struct NODE *temp; + +    // For debugging purposes and future implementations, lock the list. +    pthread_mutex_lock(&list->listLock); + +    // Free every node in the list. +    while (current != NULL) { +        temp = current; +        current = current->next; +        free(temp); +    } + +    pthread_mutex_unlock(&list->listLock); +} + +static void * counterThread(void * arg) { +    /* +     * counterThread() +     */ +    char name; +    char line[LEN_LINE]; +    char *token; +    struct timespec requestedTime; +    struct timespec remainingTime; + +    name = (char) arg; +    requestedTime.tv_sec = threadDelay / 1000; +    requestedTime.tv_nsec = threadDelay % 1000 * 1000000; +    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + +    #ifdef atcdebug +    fprintf(stderr, "counter: name == %c, numLines == %d, threadDelay == %d\n", name, numLines, threadDelay); +    #endif + +    while (TRUE) { + +        // Sleep for allotted time. +        sleeper(&requestedTime, &remainingTime); + +        if (numLines == 1) { +            getFromSingleBuffer(&buffer, line); +        } +        else { +            getFromBuffer(&buffer, line); +        } + +        // Get the first word in the line. +        token = strtok(line, " "); + +        // With each word, see if there are an even or odd number of characters +        // and insert the word into the designated list. Then print the name +        // of the thread on stdout. +        while (token != NULL) { + +            if (strlen(token) % 2 == 0) { +                putInList(&evenList, token); + +                #ifndef atcdebug +                printf("%c ", name); +                #endif + +            } +            else { +                putInList(&oddList, token); + +                #ifndef atcdebug +                printf("%c ", name); +                #endif + +            } + +            token = strtok(NULL, " "); +        } + +    } + +    return NULL; +} + +static void createThread() { +    /* +     * createThread() +     */ + +     // Would a new thread put us over the maximum allowed? +     // If not, create another counter thread as requested. + +     if (((nextThread - 'a') < maxCounters)) { +         #ifdef atcdebug +         fprintf(stderr, "reader: creating thread, name == %c\n", nextThread); +         #endif + +         pthread_create(&threadPool[nextThread - 'a'], NULL, counterThread, (void *) nextThread); +         nextThread++; +     } + +} + + +// **** Main **** +int main(int argc, char *argv[]) { +    /* +     * main() acts as the reader thread, and therefore the producer. +     */ +    char line[LEN_LINE]; +    int i; +    FILE *textFile; +    struct timespec requestedTime; +    struct timespec remainingTime; + +    // Get command line args. +    if (argc < 10) { +        fprintf(stderr, USAGE); +        exit(1); +    } + +    numLines = maxCounters = fileDelay = threadDelay = -1; +    i = 1; +    errno = 0; + +    while (argv[i] && i < 9) { + +        // Get numLines. +		if (strcmp(argv[i], "-b") == 0) { +            i++; + +			if (argv[i]) { +                numLines = strtol(argv[i], NULL, 10); + +                if (errno != 0 || numLines <= 0) { +                    fprintf(stderr, "counter: num_lines must be a positive, non-zero integer.\n"); +                    exit(1); +                } + +            } +            else { +                fprintf(stderr, USAGE); +                exit(1); +            } + +		} +        // Get maxCounters. +		else if (strcmp(argv[i], "-t") == 0) { +            i++; + +            if (argv[i]) { +                maxCounters = strtol(argv[i], NULL, 10); + +                if (errno != 0 || maxCounters <= 0 || maxCounters > 26) { +                    fprintf(stderr, "counter: max_counters must be a positive, non-zero integer no greater than 26.\n"); +                    exit(1); +                } + +            } +            else { +                fprintf(stderr, USAGE); +                exit(1); +            } + +        } +        // Get fileDelay. +        else if (strcmp(argv[i], "-d") == 0) { +            i++; + +            if (argv[i]) { +                fileDelay = strtol(argv[i], NULL, 10); + +                if (errno != 0 || fileDelay < 0) { +                    fprintf(stderr, "counter: file_delay must be a positive integer.\n"); +                    exit(1); +                } + +            } +            else { +                fprintf(stderr, USAGE); +                exit(1); +            } + +        } +        // Get threadDelay. +        else if (strcmp(argv[i], "-D") == 0) { +            i++; + +            if (argv[i]) { +                threadDelay = strtol(argv[i], NULL, 10); + +                if (errno != 0 || threadDelay < 0) { +                    fprintf(stderr, "counter: thread_delay must be a positive integer.\n"); +                    exit(1); +                } + +            } +            else { +                fprintf(stderr, USAGE); +                exit(1); +            } + +        } +        else { + +            if (numLines < 0 || maxCounters < 0 +                    || fileDelay < 0 || threadDelay < 0) { +                fprintf(stderr, USAGE); +                exit(1); +            } + +        } + +        i++; +	} + +    #ifdef atcdebug +    fprintf(stderr, "reader: numLines = %d, maxCounters = %d, fileDelay = %d, " +        "threadDelay = %d\n", numLines, maxCounters, fileDelay, threadDelay); +    #endif + +    // Set up thread environment. +    initBuffer(&buffer); +    initLinkedList(&evenList); +    initLinkedList(&oddList); +    nextThread = 'a'; +    moreStuff = TRUE; + +    // Start up first counter (consumer) thread. +    createThread(); + +    // **** Reader (producer) thread **** +    textFile = NULL; +    requestedTime.tv_sec = threadDelay / 1000; +    requestedTime.tv_nsec = threadDelay % 1000 * 1000000; + +    while (argv[i]) { + +        // Open each file given in argv[]. +        if (!(textFile = fopen(argv[i], "r"))) { +            fprintf(stderr, "counter: could not open %s\n", argv[i]); +        } +        else { + +            // Read each line in the file and insert it into the buffer. +            while (fgets(line, LEN_LINE, textFile)) { +                // Strip newline. +                line[strcspn(line, "\n")] = '\0'; + +                if (numLines == 1) { + +                    // Attempt to create a new thread if function says +                    // buffer was full. +                    if (putInSingleBuffer(&buffer, line) == TRUE) { +                        createThread(); +                    } + +                } +                else { + +                    // Attempt to create a new thread if put function says +                    // buffer was full. +                    if (putInBuffer(&buffer, line) == TRUE) { +                        createThread(); +                    } + +                } + +                // Sleep for allotted time. +                while (nanosleep(&requestedTime, &remainingTime) == -1) { +                    requestedTime = remainingTime; +                } + +            } + +            fclose(textFile); +        } + +        i++; +    } + +    // Let counter threads know that there won't be any more input and wait +    // for threads to finish before printing and terminating. +    moreStuff = FALSE; + +    sleep(2); + +    for (i = 0; i < MAX_THREADS; i++) { + +        if (threadPool[i]) { +            pthread_cancel(threadPool[i]); +        } + +    } + +    printf("\n==== Words with an even number of letters ====\n"); +    printList(&evenList); +    printf("\n==== Words with an odd  number of letters ====\n"); +    printList(&oddList); +    freeList(&evenList); +    freeList(&oddList); +    exit(0); +} diff --git a/pgm5/makefile b/pgm5/makefile new file mode 100644 index 0000000..4de261f --- /dev/null +++ b/pgm5/makefile @@ -0,0 +1,11 @@ +all: counter + +counter: counter.c +	gcc -D_REENTRANT -o counter counter.c -lpthread + +debug: counter.c +	gcc -Wall -g -D_REENTRANT -Datcdebug -o counter counter.c -lpthread + +clean: +	rm -f counter +	gcc -D_REENTRANT -o counter counter.c -lpthread diff --git a/pgm5/p5test/file0 b/pgm5/p5test/file0 new file mode 100644 index 0000000..16d6515 --- /dev/null +++ b/pgm5/p5test/file0 @@ -0,0 +1,17 @@ +a +aa +aaa +aaaa +aaaaa +aaaaaa +aaaaaaa +aaaaaaaa +aaaaaaaaa +aaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaaa +aaaaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaa diff --git a/pgm5/p5test/file1 b/pgm5/p5test/file1 new file mode 100644 index 0000000..f9a742d --- /dev/null +++ b/pgm5/p5test/file1 @@ -0,0 +1,2 @@ +a a a a a a +a a a a diff --git a/pgm5/p5test/file2 b/pgm5/p5test/file2 new file mode 100644 index 0000000..0fd6f48 --- /dev/null +++ b/pgm5/p5test/file2 @@ -0,0 +1,3 @@ +aa aa aa  aa  aa  +aa aa aa +aa aa diff --git a/pgm5/p5test/file3 b/pgm5/p5test/file3 new file mode 100644 index 0000000..5234a25 --- /dev/null +++ b/pgm5/p5test/file3 @@ -0,0 +1,9 @@ +aaa aaa aaa aaa				aaa +aaa +aaa + +aaa +aaa +aaa + + diff --git a/pgm5/p5test/file4 b/pgm5/p5test/file4 new file mode 100644 index 0000000..29c981d --- /dev/null +++ b/pgm5/p5test/file4 @@ -0,0 +1,5 @@ +aaaa aaaa +aaaa aaaa +aaaa aaaa +aaaa aaaa +aaaa aaaa diff --git a/pgm5/p5test/file5 b/pgm5/p5test/file5 new file mode 100644 index 0000000..6976d6b --- /dev/null +++ b/pgm5/p5test/file5 @@ -0,0 +1,11 @@ +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa +aaaaa + diff --git a/pgm5/p5test/file6 b/pgm5/p5test/file6 new file mode 100644 index 0000000..abc805a --- /dev/null +++ b/pgm5/p5test/file6 @@ -0,0 +1 @@ +aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa aaaaaa diff --git a/pgm5/prodcons.d/Makefile b/pgm5/prodcons.d/Makefile new file mode 100644 index 0000000..174975d --- /dev/null +++ b/pgm5/prodcons.d/Makefile @@ -0,0 +1,10 @@ +CC=gcc +CFLAGS=-g -Wall -D_REENTRANT +LIBS=-lpthread + +prodcons: prodcons.c +	$(CC) $(CFLAGS) -o prodcons prodcons.c $(LIBS) + +clean: +	rm -f prodcons core.* + diff --git a/pgm5/prodcons.d/README b/pgm5/prodcons.d/README new file mode 100644 index 0000000..3c85ac4 --- /dev/null +++ b/pgm5/prodcons.d/README @@ -0,0 +1,2 @@ +Producer/Consumer with a bounded buffer. From the +linuxthreads demos. diff --git a/pgm5/prodcons.d/prodcons.c b/pgm5/prodcons.d/prodcons.c new file mode 100644 index 0000000..665c744 --- /dev/null +++ b/pgm5/prodcons.d/prodcons.c @@ -0,0 +1,124 @@ +/* The classic producer-consumer example. +   Illustrates mutexes and conditions. +   All integers between 0 and 9999 should be printed exactly twice, +   once to the right of the arrow and once to the left. */ + +#include <stdio.h> +#include <pthread.h> + +#define BUFFER_SIZE 16 + +/* Circular buffer of integers. */ + +struct prodcons +{ +  int buffer[BUFFER_SIZE];	/* the actual data */ +  pthread_mutex_t lock;		/* mutex ensuring exclusive access to buffer */ +  int readpos, writepos;	/* positions for reading and writing */ +  pthread_cond_t notempty;	/* signaled when buffer is not empty */ +  pthread_cond_t notfull;	/* signaled when buffer is not full */ +}; + +/* Initialize a buffer */ +static void +init (struct prodcons *b) +{ +  pthread_mutex_init (&b->lock, NULL); +  pthread_cond_init (&b->notempty, NULL); +  pthread_cond_init (&b->notfull, NULL); +  b->readpos = 0; +  b->writepos = 0; +} + +/* Store an integer in the buffer */ +static void +put (struct prodcons *b, int data) +{ +  pthread_mutex_lock (&b->lock); +  /* Wait until buffer is not full */ +  while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) +    { +      pthread_cond_wait (&b->notfull, &b->lock); +      /* pthread_cond_wait reacquired b->lock before returning */ +    } +  /* Write the data and advance write pointer */ +  b->buffer[b->writepos] = data; +  b->writepos++; +  if (b->writepos >= BUFFER_SIZE) +    b->writepos = 0; +  /* Signal that the buffer is now not empty */ +  pthread_cond_signal (&b->notempty); +  pthread_mutex_unlock (&b->lock); +} + +/* Read and remove an integer from the buffer */ +static int +get (struct prodcons *b) +{ +  int data; +  pthread_mutex_lock (&b->lock); +  /* Wait until buffer is not empty */ +  while (b->writepos == b->readpos) +    { +      pthread_cond_wait (&b->notempty, &b->lock); +    } +  /* Read the data and advance read pointer */ +  data = b->buffer[b->readpos]; +  b->readpos++; +  if (b->readpos >= BUFFER_SIZE) +    b->readpos = 0; +  /* Signal that the buffer is now not full */ +  pthread_cond_signal (&b->notfull); +  pthread_mutex_unlock (&b->lock); +  return data; +} + +/* A test program: one thread inserts integers from 1 to 10000, +   the other reads them and prints them. */ + +#define OVER (-1) + +struct prodcons buffer; + +static void * +producer (void *data) +{ +  int n; +  for (n = 0; n < 10000; n++) +    { +      printf ("%d --->\n", n); +      put (&buffer, n); +    } +  put (&buffer, OVER); +  return NULL; +} + +static void * +consumer (void *data) +{ +  int d; +  while (1) +    { +      d = get (&buffer); +      if (d == OVER) +	break; +      printf ("---> %d\n", d); +    } +  return NULL; +} + +int +main (void) +{ +  pthread_t th_a, th_b; +  void *retval; + +  init (&buffer); +  /* Create the threads */ +  pthread_create (&th_a, NULL, producer, 0); +  pthread_create (&th_b, NULL, consumer, 0); +  /* Wait until producer and consumer finish. */ +  pthread_join (th_a, &retval); +  pthread_join (th_b, &retval); +  return 0; +} diff --git a/pgm5/run.sh b/pgm5/run.sh new file mode 100644 index 0000000..7d75216 --- /dev/null +++ b/pgm5/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +make +cp -f counter p5test/counter +cd p5test + +./counter -b 4 -t 1 -d 0 -D 0 file0 +./counter -b 2 -t 2 -d 1000 -D 1000 file0 +./counter -b 10 -t 1 -d 0 -D 0 /usr/share/fortune/linuxcookie +./counter -b 2 -t 26 -d 0 -D 0 /usr/share/fortune/linuxcookie +./counter -b 2 -t 10 -d 0 -D 0 /usr/share/fortune/linuxcookie +./counter -b 2 -t 10 -d 0 -D 0 file{1,2,3,4,5,6} +./counter -b 1 -t 1 -d 0 -D 0 /usr/share/fortune/linuxcookie |