I tried to implement the producer consumer problem with using forks and instead of mutexes, I tried to correct the behavior with semaphores.
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h> // for semathore obviously
#include <string.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <limits.h> // for INT_MAX, INT_MIN
#include <stdlib.h> // for strtol
#include <stdint.h> // for uint64_t
#define DO_OR_DIE(x, s) \
do \
{ \
if ((x) < 0) \
{ \
perror(s); \
exit(1); \
} \
} while (0)
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("Usage: ./task1 producer(number) consumer(number)\n");
return EXIT_FAILURE;
}
char *p;
errno = 0;
long producer = strtol(argv[1], &p, 10);
if (errno != 0 || *p != '\0' || producer > INT_MAX || producer < INT_MIN)
{
// error handling
printf("producer fail\n");
printf("Usage: ./task1 producer(number) consumer(number)\n");
return EXIT_FAILURE;
}
long consumer = strtol(argv[2], &p, 10);
if (errno != 0 || *p != '\0' || consumer > INT_MAX || consumer < INT_MIN)
{
// error handling
printf("consumer fail\n");
printf("Usage: ./task1 producer(number) consumer(number)\n");
return EXIT_FAILURE;
}
if (consumer < 1 || producer < 1)
{
printf("number must be greater then 0!\n");
return EXIT_FAILURE;
}
// input is correct and we can continue with the shared memory we need of size consumer!
uint64_t *sharedmemory = mmap(NULL, (consumer 1) * sizeof(uint64_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); // share memory
if (sharedmemory == MAP_FAILED)
{
perror("mmap failed");
exit(EXIT_FAILURE);
}
uint64_t *array = sharedmemory;
// creating sem array with every element being a sem to check if it is used or not.
sem_t *sema = mmap(NULL, sizeof(sema) * consumer, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (sema == MAP_FAILED)
{
perror("mmap failed");
exit(EXIT_FAILURE);
}
for (int i = 0; i < consumer; i)
{
// creating sem entry for every array element
if (sem_init(&sema i, 1, 0) < 0)
{
perror("sem_init failed");
exit(EXIT_FAILURE);
}
}
// after creating shared memory fork 2 times
pid_t pid = fork();
DO_OR_DIE(pid, "fork1 failed!\n");
if (pid == 0)
{
// child process 1
// if Producer > Consumer then wrap around the ring buffer
for (int i = 0; i < producer; i)
{
sem_wait(&sema[i]);
// wrap around in ring buffer (i % buffer)
array[i % consumer] = i 1;
sem_post(&sema[i]);
}
munmap(sharedmemory, (consumer 1) * sizeof(uint64_t));
}
pid = fork();
DO_OR_DIE(pid, "fork2 failed!\n");
if (pid == 0)
{
// child process 2
unsigned long long result = 0;
for (int i = 0; i < producer; i)
{
sem_wait(&sema[i]);
// read from shared memory
result = array[i];
sem_post(&sema[i]);
}
array[consumer 1] = result;
munmap(sharedmemory, (consumer 1) * sizeof(uint64_t)); // sets the memory free (mmap)
}
// waiting for children
while ((pid = wait(NULL)) != -1)
;
// printing the result
printf("%ld\n", array[consumer 1]);
// cleanup
munmap(sharedmemory, (consumer 1) * sizeof(uint64_t));
for (int i = 0; i < consumer; i)
{
// creating sem entry for every array element
sem_destroy(&sema i);
}
return EXIT_SUCCESS;
}
I do also compile with the following flags:
-Wall -Wextra -lpthread -lrt -lm
The problem I'm currently facing is this error message:
cc prodcons.o -o prodcons
/usr/bin/ld: prodcons.o: in function `main':
prodcons.c:(.text 0x230): undefined reference to `sem_init'
/usr/bin/ld: prodcons.c:(.text 0x2ae): undefined reference to `sem_wait'
/usr/bin/ld: prodcons.c:(.text 0x2ef): undefined reference to `sem_post'
/usr/bin/ld: prodcons.c:(.text 0x377): undefined reference to `sem_wait'
/usr/bin/ld: prodcons.c:(.text 0x3aa): undefined reference to `sem_post'
/usr/bin/ld: prodcons.c:(.text 0x47f): undefined reference to `sem_destroy'
collect2: error: ld returned 1 exit status
make: *** [Makefile:6: prodcons] Error 1
Am I missing a header or did I implement the semaphore array wrong?
CodePudding user response:
The errors you're seeing come from the linker. It can't find the symbols in the current libraries it is searching.
We need to add the correct pthreads library (see man sem_wait
). It wants -lpthread
So, recompile with:
cc prodcons.o -o prodcons -lpthread