简体   繁体   中英

Processes with group of 2 semaphores and shared memory

I write a program containing two processes: the first one contains a group of two semaphores and creates the child process that reads all data in the shared memory segment and prints them.

In the second one, the child process computes the data using a compute function that returns 0 when all data are computed. It transmits them to the parent through the shared memory segment.

To write data:

  • On the 1st semaphore the child makes P and the parent make V.

  • On the 2nd semaphore the child makes V and the parent make P.

But as I'm new in this topic and still getting hardness to understand, it seems like I'm doing something wrong because it's not working as it has to be.

Here is my code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>

int sum =0;

int compute(int data){
    sum += data;
    return sum;
}

int main(){
    int i;
    int shm_id;
    int data;
    pid_t pid;
    key_t shm_key;
    sem_t *sem;
    // unsigned int sem_value =2;
    shm_key = ftok("/dev/null", 65);
    shm_id = shmget(shm_id, sizeof(int), 0644 | IPC_CREAT);
    if (shm_id < 0){
        perror("shmgget");
        exit(EXIT_FAILURE);
    }
    // data = shmat(shm_id, NULL, 0);
    sem = sem_open("semaphore", O_CREAT | O_EXCL, 0644, 2);

    for (i = 0; i < 2; i++){
        pid = fork();
        if (pid < 0)
        {
            perror("fork");
            sem_unlink("semaphore");
            sem_close(sem);
            exit(EXIT_FAILURE);
        }
        else if (pid == 0)
        {
            break;
        }
    }
    if (pid == 0)
    {
        puts("Enter the data:");
        scanf("%d", &data);
        //child process
        sem_wait(sem);
        printf("Child - %d is in critical section\n", i);
        sleep(1);

        puts("Enter the data:");
        scanf("%d", &data);
        // *shrd_value += data;
        printf("Child - %d: new value of data = %d\n", i, data);
        printf("Child - %d: sum of whole data by far = %d\n", i, compute(data));
        sem_post(sem);
        exit(EXIT_SUCCESS);
    }
    else if (pid > 0)
    {
        //parent process
        while (pid = waitpid(-1, NULL, 0))
        {
            if (errno == ECHILD)
            {
                break;
            }
        }
        puts("All children exited");
        shmdt(&data);
        shmctl(shm_id, IPC_RMID, 0);
        sem_unlink("semaphore");
        sem_close(sem);         
        exit(0);
    }
}

Output:

Enter the data:
Enter the data:
2
Child - 0 is in critical section
1Enter the data:

Child - 1 is in critical section
Enter the data:
3
Child - 0: new value of data = 3
Child - 0: sum of whole data by far = 3
2
Child - 1: new value of data = 2
Child - 1: sum of whole data by far = 2
All children exited

I have also modified the way they write to shared memory: they write directly at the address given by shmat call that is missing in your code. I have fixed some bugs and simplifed the code (removed the array - added detailed logging especially before and after entering the critial section):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/wait.h>

int main(){
    int i;
    int shm_id;
    pid_t pid;
    int *addr; 
    int data;
    pid_t current_pid;
    key_t shm_key;
    sem_t *sem;

    shm_key = ftok("/dev/null", 65);
    shm_id = shmget(shm_key, sizeof(int), 0644 | IPC_CREAT);
    if (shm_id < 0){
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    sem_unlink("semaphore");
    sem = sem_open("semaphore", O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    } 

    addr = (int *) shmat(shm_id, (void *) 0, 0);   
    if (addr == (void *) -1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    *addr = 0;

    for (i = 0; i < 2; i++){
        pid = fork();
        if (pid < 0)
        {
            perror("fork");
            sem_close(sem);
            sem_unlink("semaphore");
            exit(EXIT_FAILURE);
        }
    }


    if (pid == 0)
    {
    current_pid = getpid();
        printf("Child %d: waiting for critical section \n", current_pid);
        sem_wait(sem);
        printf("Child %d: enters in critical section \n", current_pid);
        printf("child %d: Enter the data:\n", current_pid);
        scanf("%d", &data);
        printf("Child %d: new value of data = %d\n", current_pid, data);
        printf("Child %d: sum of whole data so far = %d\n", current_pid, *addr += data);
        sem_post(sem);
    printf("Child %d exits from critical section\n", current_pid);
        exit(EXIT_SUCCESS);
    }
    else if (pid > 0)
    {
        //parent process
        while (pid = waitpid(-1, NULL, 0))
        {
            if (errno == ECHILD)
            {
                break;
            }
        }
        puts("All children exited");
        shmdt(addr);
        shmctl(shm_id, IPC_RMID, 0);
        sem_close(sem);         
        sem_unlink("semaphore");
        exit(0);
    }

    exit(0);
}

Note that semaphore initial value must be 1 to have a true critical section for 2 processes.

I have also removed the sleep calls and we can see that one of the process is waiting:

Child 22514: waiting for critical section 
Child 22514: enters in critical section 
child 22514: Enter the data:
Child 22515: waiting for critical section 
333
Child 22514: new value of data = 333
Child 22514: sum of whole data so far = 333
Child 22514 exits from critical section
Child 22515: enters in critical section 
child 22515: Enter the data:
666
Child 22515: new value of data = 666
Child 22515: sum of whole data so far = 999
Child 22515 exits from critical section
All children exited
All children exited

Here's the code with producer and consumer process

#include <stdio.h> 
#include <stdlib.h>
#include <fcntl.h>         // O_CREAT, O_EXEC
#include <errno.h>         // errno, ECHILD     
#include <unistd.h>
#include <sys/shm.h>       // shmat(), IPC_RMID
#include <sys/wait.h> 
#include <semaphore.h>     // sem_open(), sem_destroy(), sem_wait()...
#include <sys/types.h>     // key_t, sem_t, pid_t
#include <pthread.h>

#define BUFF 10

typedef struct data{
    int buff[BUFF];
    int size;
    int index;
}DATA;

int main(int argc, char const *argv[])
{
    sem_t *full, *empty, *access;
    key_t shm_key;
    int shm_id;
    full = sem_open ("fullname", O_CREAT , 0644, 15); 
    empty = sem_open ("empty", O_CREAT , 0644, 0);
    access = sem_open ("access", O_CREAT , 0644, 1);

    if (argc!=2)
    {
        exit(1);
    }

    int value=atoi(argv[1]);

    //initialize a shared variable in shared memory
    shm_key = ftok("/dev/null", 60);
    shm_id = shmget(shm_key, sizeof(DATA), 0);
    // shared memory error check
    if (shm_id < 0){
        shm_id = shmget(shm_key, sizeof(DATA), 0644 | IPC_CREAT);
        DATA *data = (DATA*) shmat (shm_id, NULL, 0);
        data->size=0;
        data->index=0; //index 
    }
    printf("Shared memory id: %d\n",shm_id );


    printf("Checking buffer...,\n");
    //If in the buffer have free space then will wait for consumer to consume the data\n"
    sem_wait(empty);

    printf("\nLocking buffer to produce data\n");
    sem_wait(access);


    //initialize a shared variable in shared memory
    shm_key = ftok("/dev/null", 60);
    shm_id = shmget(shm_id, sizeof(DATA), 0644 | IPC_CREAT);
    // shared memory error check
    if (shm_id < 0){
        perror("semaphore");
        exit(EXIT_FAILURE);
    }

    //Shared variable  
    DATA *data = (DATA*) shmat (shm_id, NULL, 0);
    int index=(data->size + data->index) % 15;

    data->buff[index]=value;
    data->size++;
    printf("%d is located in %d on the buffer\n",value,index );



    //consusming

    // attach data to shared memory

    index=data->index;
    value=data->buff[index];

    printf("%d now consumed\n",value );
    data->size--;
    data->index++;



    sem_post(access);
    sem_post(full);



    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM