Producer - Consumer problem using POSIX semaphores

Operating System lab is an interesting one in the seventh semester. Producer - consumer problem is one of the exercises to be done at the lab. When I was exploring semaphores, I came across two standards, System V and POSIX semaphores. System V seems to be older standard and they are are complex. It requires little bit of setting up steps to use them. Everyone were following System V semaphores. I thought of giving POSIX a try since it is newer, cleaner and easier to use.

To those who are new to semaphores:

Semaphore is an unsigned special integer type. It is used for synchronization. It can take values 0 or any positive value. When semaphore is decremented, it possess a special property. If the value of semaphore is 0 and decrement operation is performed, it will not decrement immediately, instead it wait until the value becomes positive and then it decrements the value and proceeds to next statement after decrement operation. Semaphores are used in synchronization when a common data is to be accessed by multiple processes or threads or for resource allocation.

For more, see Wikipedia

Producer - Consumer problem is a resource allocation problem. There is a common data called buffer which consists of N slots. Producer and Consumer are two parties who can access the buffer. Producer produces items and place it in slots of the buffer until N slots becomes full. A consumer is a party who removes the items from the buffer. A producer can produce an item and place it to buffer only when buffer has atleast one empty slot. A consumer can consume an item only when there is atleast one slot is filled in the buffer. The problem here is to control the producer and consumer. When no slot is empty, producer should wait until a slot beomes free to make next production of an item. When buffer is empty, consumer should wait until atleast one slot becomes filled. It can be easily solved with semaphores and shared memory.

Here is the code:

Header file: problem.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <fcntl.h>

#define BUFFER_SIZE 10
#define CONSUMER_SLEEP_SEC 3
#define PRODUCER_SLEEP_SEC 1
#define KEY 1010

// A structure to store BUFER and semaphores for synchronization
typedef struct
{
	int buff[BUFFER_SIZE];
	sem_t mutex, empty, full;

} MEM;

// Method for shared memory allocation
MEM *memory()
{
	key_t key = KEY;
	int shmid;
	shmid = shmget(key, sizeof(MEM), IPC_CREAT | 0666);
	return (MEM *) shmat(shmid, NULL, 0);
}

void init()
{
	// Initialize structure pointer with shared memory
	MEM *M = memory();

	// Initialize semaphores
	sem_init(&M->mutex,1,1);
	sem_init(&M->empty,1,BUFFER_SIZE);
	sem_init(&M->full,1,0);
}

File: producer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "problem.h"

void producer()
{
	int i=0,n;
	MEM *S = memory();

	while(1)
	{
		i++;
		sem_wait(&S->empty); // Semaphore down operation
		sem_wait(&S->mutex);
		sem_getvalue(&S->full,&n);
		(S->buff)[n] = i; // Place value to BUFFER
		printf("[PRODUCER] Placed item [%d]\n", i);
		sem_post(&S->mutex);
		sem_post(&S->full); // Semaphore up operation
		sleep(PRODUCER_SLEEP_SEC);

	}
}

main()
{
	init();
	producer();

}

File: consumer.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "problem.h"

void consumer()
{
	int n;
	MEM *S = memory();

	while(1)
	{

		sem_wait(&S->full); // Semaphore down operation
		sem_wait(&S->mutex); // Semaphore for mutual exclusion
		sem_getvalue(&S->full,&n); // Assign value of semphore full, to integer n
		printf("[CONSUMER] Removed item [%d]\n", (S->buff)[n]);
		sem_post(&S->mutex); // Mutex up operation
		sem_post(&S->empty); // Semaphore up operation
		sleep(CONSUMER_SLEEP_SEC);

	}
}

main()
{
	consumer();
}

Compile above programs as:

1
2
$ gcc producer.c -lrt -o producer
$ gcc consumer.c -lrt -o consumer

Open two terminals and run producer on first terminal and consumer on second terminal.

Happy Hacking!