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.