Hey all,
I am relatively new to C programming and need to write a program that uses semaphores to control access to shared memory that places items into a circular buffer. The problem I have is one where the consumer runs out of things to consume and the producer doesn't wake up to place anything new into the buffer. I have the following code, which gives the output below it. I have been looking at this now for days and just seem to be going around in circles. Ay help would be appreciated.
Thanks,
Terry
Code:
#define _SVID_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#define BUFFER_SIZE 10
#define ERROR_CHAR (-1)
#define MAX_FILE_SIZE 256
#define TRUE 1
#define FALSE 0
void buffer_char(char *c);
char* unbuffer_char(void);
typedef struct
{
char file_path[BUFFER_SIZE][MAX_FILE_SIZE];
int head;
int tail;
sem_t full;
sem_t empty;
sem_t mutex;
} Buffer;
Buffer *buffer_ptr;
int main(int argc, char** argv)
{
int shmid;
pid_t prod_pid, con_pid;
/* shmid is the id of the shared memory address for our buffer */
shmid = shmget(IPC_PRIVATE, getpagesize(), IPC_CREAT | 0666);
/* get a pointer to our buffer in shared memory */
buffer_ptr = (Buffer*) shmat(shmid, NULL, 0);
/* initialise the buffer */
buffer_ptr->head = 0;
buffer_ptr->tail = 0;
/* initialise our semaphores (2nd param 1 means shared betweeen processes */
sem_init(&buffer_ptr->empty, 1, BUFFER_SIZE);
sem_init(&buffer_ptr->full, 1, 0);
sem_init(&buffer_ptr->mutex, 1, 1);
/* spawn our child processes */
prod_pid = fork();
if (prod_pid == 0)
{
/* this is the producer process */
int i;
char items[15][10] = {"File 1", "File 2", "File 3", "File 4", "File 5", "File 6", "File 7", "File 8", "File 9", "File 10", "File 11", "File 12", "File 13", "File 14", "File 15"};
for (i = 0; i < 15; i++)
{
sem_wait(&buffer_ptr->empty);
sem_wait(&buffer_ptr->mutex);
printf("Buffering %s\n", items[i]);
buffer_char(items[i]);
sem_post(&buffer_ptr->mutex);
sem_post(&buffer_ptr->full);
}
exit(0);
}
con_pid = fork();
if (con_pid == 0)
{
/* this is the consumer process */
while (TRUE)
{
sem_wait(&buffer_ptr->full);
sem_wait(&buffer_ptr->mutex);
printf("Unbeffering %s\n", unbuffer_char());
sem_post(&buffer_ptr->mutex);
sem_post(&buffer_ptr->empty);
}
exit(0);
}
if (prod_pid != 0 && con_pid != 0)
{
/* this is the main process so wait here for both processes to finish before closing out and finishing */
wait(prod_pid);
wait(con_pid);
printf("************************************");
/* detach the shared memory and deallocate the memory segment */
shmdt(&buffer_ptr);
shmctl(shmid, IPC_RMID, 0);
/* finally, close the signature file */
return (EXIT_SUCCESS);
}
}
void buffer_char(char* c)
{
/* Use modulo as a trick to wrap around the end of the buffer back to the beginning */
if ((buffer_ptr->tail + 1) % BUFFER_SIZE != buffer_ptr->head)
{
strcpy(buffer_ptr->file_path[buffer_ptr->tail], c);
buffer_ptr->tail = (buffer_ptr->tail + 1) % BUFFER_SIZE;
}
}
char* unbuffer_char(void)
{
if (buffer_ptr->tail != buffer_ptr->head)
{
char *temp = buffer_ptr->file_path[buffer_ptr->head];
buffer_ptr->head = (buffer_ptr->head + 1) % BUFFER_SIZE;
printf("Head: %d\n", buffer_ptr->head);
printf("Tail: %d\n", buffer_ptr->tail);
return (temp);
}
else
{
printf("Problem is here!\n");
printf("Head: %d\n", buffer_ptr->head);
printf("Tail: %d\n", buffer_ptr->tail);
}
}
Output:
Code:
Buffering File 1
Buffering File 2
Buffering File 3
Buffering File 4
Buffering File 5
Buffering File 6
Buffering File 7
Buffering File 8
Buffering File 9
Buffering File 10
Head: 1
Tail: 9
Unbeffering File 1
Head: 2
Tail: 9
Unbeffering File 2
Head: 3
Tail: 9
Unbeffering File 3
Head: 4
Tail: 9
Unbeffering File 4
Head: 5
Tail: 9
Unbeffering File 5
Head: 6
Tail: 9
Unbeffering File 6
Head: 7
Tail: 9
Unbeffering File 7
Head: 8
Tail: 9
Unbeffering File 8
Head: 9
Tail: 9
Unbeffering File 9
Problem is here!
Head: 9
Tail: 9