0

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.

  • 1
    _proces1_ sends a SIGUSR1 to its parent (`getppid`), which is presumably your shell. You mean instead to signal _proces2_, whose PID you do not record. – pilcrow Dec 19 '22 at 15:31
  • 1
    You should also be aware that a signal handler set by `signal` may be reset to the default when the handler is invoked. You should use [`sigaction`](https://man7.org/linux/man-pages/man2/sigaction.2.html) instead. – Hasturkun Dec 19 '22 at 15:37
  • 1
    Expanding on @Hasturkun, read this: [**What is the difference between sigaction and signal?**](https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal) – Andrew Henle Dec 19 '22 at 15:43

0 Answers0