1

For my assignment, I have to solve a simplified Conway's problem using lightweight processes and constant size buffers. The program reads a stream of characters, packages the stream into 10-character blocks, and write them as 24-character lines. The pound sign ('#') character will be used as an end-of-data (EOD) sentinel value. We have to implement the following changes:

After every block an extra blank is inserted.

Every adjacent pair of asterisks is replaced by an exclamation point. Asterisks are considered adjacent only if they are in the same block.

I have never programmed in C, and this is giving me fits. We were given the main routine the prototypes for the three processes and the buffer operations. So far, after many hours, I've only managed to get the buffers up and working. Here is the main routine and the function prototypes and definitions.

typedef struct {
    char *buf;         /* Buffer array */         
    int n;             /* Maximum number of slots */
    int front;         /* buf[(front+1)%n] is first item */
    int rear;          /* buf[rear%n] is last item */
    sem_t mutex;       /* Protects accesses to buf */
    sem_t slots;       /* Counts available slots */
    sem_t items;       /* Counts available items */
    } sbuf_t;

/* Function prototypes: */
void sbuf_init(sbuf_t *sp, int n);
void sbuf_deinit(sbuf_t *sp);
void sbuf_insert(sbuf_t *sp, char item);
char sbuf_remove(sbuf_t *sp);

void* ReadInput(void * vargp);    /* ReadInput thread routine prototype   */
void* Squash(void * vargp);       /* Squash thread routine prototype      */
void* PrintOutput(void * vargp);  /* PrintOutput thread routine prototype */


/* Global constants */
const int BLOCKMAX=10;      /* Length of input "blocks" */
const int LINEMAX=24;       /* Length of output "lines" */
const char EODsentinel='#'; /* End-Of-Data Sentinel value */


/* Global (shared) buffers */
sbuf_t rdbuf; /* Synchronized buffer between ReadInput and Squash   */
sbuf_t prbuf; /* Synchronized buffer between Squash and PrintOutput */


int main(int argc, char* argv[]) 
{
    pthread_t tidReadInput, tidSquash, tidPrintOutput;

    int rdbufsize;    /* buffer size between ReadInput and Squash   */
    int prbufsize;    /* buffer size between Squash and PrintOutput */


    /* Process input arguments */
    if (argc != 3) { 
        printf("usage: %s <rdbufsize> <prbufsize>\n", argv[0]);
        printf("  Using defaults: <rdbufsize=4> <prbufsize=7>\n");
       rdbufsize = 4;
       prbufsize = 7;
    }
    else
    {
        rdbufsize = atoi(argv[1]);
        prbufsize = atoi(argv[2]);
    }

    /* Create shared FIFO buffers */
    sbuf_init(&rdbuf, rdbufsize);
    sbuf_init(&prbuf, prbufsize);

    /* Create threads and wait for them to finish */
    Pthread_create(&tidReadInput,   NULL, ReadInput,   NULL);
    Pthread_create(&tidSquash,      NULL, Squash,      NULL);
    Pthread_create(&tidPrintOutput, NULL, PrintOutput, NULL);

    Pthread_join(tidPrintOutput, NULL);


    /* Clean up shared FIFO buffers */
    printf("\n---cleaning up---\n");
    sbuf_deinit(&rdbuf);
    sbuf_deinit(&prbuf);

    printf("\n---finished---\n");
    exit(0);
}

Here are the buffer operations.

/* Create an empty, bounded, shared FIFO buffer with n slots */
void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = Calloc(n, sizeof(char)); 
    sp->n = n;                       /* Buffer holds max of n items */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear */
    Sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking */
    Sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots */
    Sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}

/* Clean up buffer sp */
void sbuf_deinit(sbuf_t *sp)
{
    Free(sp->buf);
}

/* Insert item onto the rear of shared buffer sp */
void sbuf_insert(sbuf_t *sp, char item)
{
    P(&sp->slots);                   /* Wait for available slot */
    P(&sp->mutex);               /* Lock the buffer */
        sp->buf[(++sp->rear)%(sp->n)] = item;   /* Insert the item */
    V(&sp->mutex);               /* Unlock the buffer */
    V(&sp->items);                   /* Announce available item */
}

/* Remove and return the first item from buffer sp */
char sbuf_remove(sbuf_t *sp)
{
    char item;
    P(&sp->items);                   /* Wait for available item */
        P(&sp->mutex);               /* Lock the buffer */
            item = sp->buf[(++sp->front)%(sp->n)];  /* Remove the item */
        V(&sp->mutex);               /* Unlock the buffer */
    V(&sp->slots);                   /* Announce available slot */
    return item;
}

Here are my 3 routines and what I've got so far.

/* ReadInput thread routine */
void* ReadInput(void * vargp)
{
    char ch;
    char newline;

    scanf("%c%c", &ch, &newline);

    while (ch != EODsentinel)
    {
        sbuf_insert(&rdbuf, ch);

        scanf("%c%c", &ch, &newline);
    }
    sbuf_insert(&rdbuf, EODsentinel);

    printf("ReadInput finished\n");

    return NULL;
}

/* Squash thread routine */
void* Squash(void * vargp)
{
    char ch;

    ch = sbuf_remove(&rdbuf);
    while (ch != EODsentinel)
    {
        sbuf_insert(&prbuf, ch);

        ch = sbuf_remove(&rdbuf);
    }
    sbuf_insert(&prbuf, EODsentinel);

    printf("Squash finished\n");

    return NULL;
}

/* PrintOutput thread routine */
void* PrintOutput(void * vargp)
{
    char ch;

    ch = sbuf_remove(&prbuf);
    while (ch != EODsentinel)
    {
        printf("%c", ch);

        ch = sbuf_remove(&prbuf);
    }

    printf("\n");

    printf("PrintOutput finished\n");

    return NULL;
}

All my code does now is reads the input passes it between buffers and prints it out. I know what I need to do but am unsure how to do it. I need to add the line break logic to PrintOutput, add the space adding logic to ReadInput, and add the asterisk exclamation logic to Squash. My main problem is using the buffers and adding the logic where appropriate. C is new to me and this is very confusing.

kemotoe
  • 1,730
  • 13
  • 27
  • @ElliotFehr I don't want a complete solution. Was just looking for a little guidance. – kemotoe Apr 21 '15 at 16:32
  • 4
    Tip for you - You could simply present ***only the issue*** you are trying to solve. It appears you have most of what you need to do nailed, and have questions about small parts. Isolate those small parts, present them as specific questions, each with a ***[small but complete compilable code snippet](http://sscce.org/)*** that illustrates the issue or question you have. You will always get a better response if you can do this. – ryyker Apr 21 '15 at 16:33
  • 2
    @ryyker Thank you. I will try to rework the question and post it. – kemotoe Apr 21 '15 at 16:43
  • @kemotoe - you are welcome... Here is a clarification: instead of presenting almost 6000 characters of content in a question, you could simply ask _how does one search and replace characters in a block of text?_, then present a small snippet of code showing what you have tried. (this is simplified example, but if generally followed, will yield a better response) – ryyker Apr 21 '15 at 16:43
  • In reading the problem description, all the buffer manipulation is completely unnecessary. Rather a 'state machine' would be sufficient. There are only a few candidates for the state transitions. for instance: 1) 10 characters have been output 2) an asterisk has been input 3) two 'blocks' have been output. so need a couple of counters and a couple of flags and not much of anything else. I.E. no buffer – user3629249 Apr 21 '15 at 16:55
  • a few suggestions: 1) use meaningful variable names. 'P', etc is NOT meaningful. 2) do not 'typedef' struct definitions. rather, use 'struct tagname' when ever you might have used the typedef name, There is nothing in the problem description about using threads and semaphores, so why complicate the problem by including such structures? – user3629249 Apr 21 '15 at 17:00
  • If you can use constant size buffers, I'd do away with all of the dynamic memory allocation using `calloc` and `free`. Use `char buf[ POUND_DEFINED_SIZE ]` , for example. – davepmiller Apr 21 '15 at 17:02
  • @user3629249 We had to create the threads and were given the buffer operations that had to be used in the solution. – kemotoe Apr 21 '15 at 17:08
  • What are `P()` and `V()`? – alk May 01 '15 at 12:11

0 Answers0