I had to develop a set of producer-consumer programs implementing the following interprocess communication scheme using the semaphore mechanism and shared memory in C: Process 1 reads data from the standard input stream or file and passes it to process 2. Process 2 retrieves the data sent by process 1, calculates the number of characters in each line and passes the determined number to process 3. Process 3 takes the data produced by process 2 and puts it into the standard output stream. Each received data unit should be output on a separate line.
I created this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <signal.h>
#define SHM_SIZE 1024
#define SEM_KEY 12345
int shm_id;
int sem_id;
char *shm_ptr;
// Handle the SIGUSR1 signal for process 1
void proces1_handler(int signo)
{
if (signo == SIGUSR1)
{
// Send a signal to process 2 to read the communication link
kill(getppid(), SIGUSR2);
}
else if (signo == SIGUSR2)
{
// Sending a signal to process 2 about reading the communication link
kill(getppid(), SIGUSR1);
}
else if (signo == SIGINT)
{
// Sending a signal to process 2 about the completion of work
kill(getppid(), SIGINT);
}
}
// SIGUSR1 signal handling for process 2
void proces2_handler(int signo)
{
if (signo == SIGUSR1)
{
// Sending a signal to the parent process about reading the communication link
kill(getppid(), SIGUSR1);
}
else if (signo == SIGUSR2)
{
// Sending a signal to the parent process about reading the communication link
kill(getppid(), SIGUSR2);
}
else if (signo == SIGINT)
{
// Sending a signal to process 3 about the completion of work
kill(getppid(), SIGINT);
}
}
// SIGUSR1 signal handling for process 3
void proces3_handler(int signo)
{
if (signo == SIGUSR1)
{
// Awaiting semaphore access
semop(sem_id, &(struct sembuf){ 0, -1, 0 }, 1);
}
else if (signo == SIGINT)
{
// Semaphore release
semop(sem_id, &(struct sembuf){ 0, 1, 0 }, 1);
// Semaphore removal
semctl(sem_id, 0, IPC_RMID);
// Detach shared memory from the process
shmdt(shm_ptr);
// Removal of shared memory
shmctl(shm_id, IPC_RMID, NULL);
// Ending the process 3
exit(0);
}
}
void proces1(int pipe_fd[2])
{
FILE *fp;
char buffer[SHM_SIZE];
int n;
// Open a file or input stream
fp = fopen("dane.txt", "r");
if (fp == NULL)
fp = stdin;
// Data reading loop
while (fgets(buffer, SHM_SIZE, fp) != NULL)
{
// Transferring data to the process 2
strcpy(shm_ptr, buffer);
// Sending a signal to the process 2
kill(getppid(), SIGUSR1);
// Waiting for the process to read data 2
pause();
// Sending a signal to process 2 about reading the communication link
kill(getppid(), SIGUSR2);
}
// Sending a signal to process 2 that there is no more data
kill(getppid(), SIGINT);
// Closing a file or input stream
if (fp != stdin)
fclose(fp);
}
void proces2(int pipe_fd[2])
{
char buffer[SHM_SIZE];
int n;
// Loop receiving data from process 1
while (1)
{
// Waiting for signal from process 1
pause();
// Reading data from shared memory
strcpy(buffer, shm_ptr);
// Calculation of the number of characters
n = strlen(buffer);
// Saving the number of characters to the communication link
write(pipe_fd[1], &n, sizeof(int));
// Sending a signal to the parent process about reading the communication link
kill(getppid(), SIGUSR1);
// Waiting for the parent process to read the communication link
pause();
// Sending a signal to the parent process about reading the communication link
kill(getppid(), SIGUSR2);
// Waiting for the process to read the communication link 3
semop(sem_id, &(struct sembuf){ 0, -1, 0 }, 1);
// Sending a signal to process 3 about the need to read the communication link
kill(getppid(), SIGUSR1);
}
}
void proces3(int pipe_fd[2])
{
int n;
// Loop receiving data from the process 2
while (1)
{
// Waiting for signal from process 2
pause();
// Reading the number of characters from the communication link
read(pipe_fd[0], &n, sizeof(int));
// Output the number of characters to the standard output
printf("%d\n", n);
// Semaphore release
semop(sem_id, &(struct sembuf){ 0, 1, 0 }, 1);
}
}
int main(int argc, char *argv[])
{
pid_t pid;
int pipe_fd[2];
union sigval value;
// Create shared memory
shm_id = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666);
if (shm_id < 0)
{
perror("shmget error");
exit(1);
}
// Connecting shared memory to the process
shm_ptr = shmat(shm_id, NULL, 0);
if (shm_ptr == (void *)-1)
{
perror("shmat error");
exit(1);
}
// Creating a semaphore
sem_id = semget(SEM_KEY, 1, IPC_CREAT | 0666);
if (sem_id < 0)
{
perror("semget error");
exit(1);
}
// Semaphore initialization
if (semctl(sem_id, 0, SETVAL, 1) < 0)
{
perror("semctl error");
exit(1);
}
// Creating a communication link
if (pipe(pipe_fd) < 0)
{
perror("pipe error");
exit(1);
}
// Signal handling setting
signal(SIGUSR1, proces1_handler);
signal(SIGUSR2, proces1_handler);
signal(SIGINT, proces1_handler);
// Creating a process 2
pid = fork();
if (pid == 0)
{
// Ustawienie obsługi sygnałów
signal(SIGUSR1, proces2_handler);
signal(SIGUSR2, proces2_handler);
// Process function call 2
proces2(pipe_fd);
exit(0);
}
// Process creation 3
pid = fork();
if (pid == 0)
{
// Signal handling setting
signal(SIGUSR1, proces3_handler);
// Process function call 3
proces3(pipe_fd);
exit(0);
}
// Calling a process function 1
proces1(pipe_fd);
// Waiting for processes 2 and 3 to complete
wait(NULL);
wait(NULL);
// Detach shared memory from the process
shmdt(shm_ptr);
// Removal of shared memory
shmctl(shm_id, IPC_RMID, NULL);
// Termination of the parent process
exit(0);
}
But instead of printing the answer it ends with 'User defined signal 1' or just termination. Could someone help with this one?
I tried adding if statements for checking values returned by functions like kill, semop etc but this didnt help.