1

I have the following program:

#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100

void ChildProcess(void);
void ParentProcess(void);

void main(void)
{
    pid_t pid;
    pid = fork();
    
    if (pid == 0)
        ChildProcess();
     else
        ParentProcess();
}

void ChildProcess(void)
{
    int i;
    for (i = 1; i <= MAX_COUNT; i++)
        printf(" This line is from child, value = %d\n", i);
    printf(" *** Child process is done ***\n");
}

void ParentProcess(void)
{
    int i;
    for (i = 1; i <= MAX_COUNT; i++)
        printf("This line is from parent, value = %d\n", i);
    printf("*** Parent is done ***\n");
}

I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:

  • Create and initialize the shared memory in the parent.
  • Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
  • Fork from the parent to the child.
  • If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.

Expected output

What I did in the ParentProcess function is the following:

void ParentProcess(void)
{
    int i;
    
    for (i = 1; i <= MAX_COUNT; i++)
        printf("This line is from parent, value = %d\n", i);
    printf("*** Parent is done ***\n");
    
    int localVar = 0;
    int* p = (int*) malloc(2);
    pid_t childPID = fork();
    *p = 0;
    
    if (childPID >= 0)
    {
        printf("\nChild process has started\n");
        if (childPID == 0)
        {
            localVar++;
            globalVar++;
            printf("Child process has found the following data %d,", *p);
            *p = 70;
            printf( " %d,", *p); 
            *p = 66; 
            printf(" %d,", *p); 
            *p = 51; 
            printf(" %d,", *p); 
            *p = 90; 
            printf(" %d in shared memory\n",*p); 
            
            printf("Child is existing\n\n");
        } 
    } 
   
}

And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?

If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance

Ray Xm
  • 11
  • 1

2 Answers2

1

It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)

So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here How to use shared memory with Linux in C

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>

void *create_shared_memory(size_t size)
{
    int protection = PROT_READ | PROT_WRITE;
    int visibility = MAP_SHARED | MAP_ANONYMOUS;
    return mmap(NULL, size, protection, visibility, -1, 0);
}

int main()
{
    // Allocate 4 ints
    void *shmem = create_shared_memory(sizeof(int)*4);

    if( shmem == NULL ){
        fprintf(stderr, "Failed to create shared memory\n");
        return -1;
    }

    // Initialize 4 ints
    ((int*)shmem)[0] = 10;
    ((int*)shmem)[1] = 100;
    ((int*)shmem)[2] = 1000;
    ((int*)shmem)[3] = 10000;

    int pid = fork();

    if (pid == 0)
    {
        // Print 4 ints in child
        printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
        printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
        printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
        printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
        printf("Child end\n");
    }
    else
    {
        printf("Parent waiting for child ends...\n");
        waitpid(pid, NULL, 0);
        printf("Parent ends\n");
    }

    int ret = munmap(shmem, sizeof(int)*4);
    if( ret != 0 ){
        fprintf(stderr, "Failed to unmap shared memory\n");
        return -1;
    }

    return 0;
}
Shu Suzuki
  • 1,164
  • 11
  • 19
1

I've written a small piece of c code which you might find helpful:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>

#define NUM_INTS    5

int main(int argc, char *argv[])
{
    key_t key = (key_t) 123456;
    int shmgetrc, semgetrc;
    struct shmid_ds ds;
    int *shared_values;
    int i;
    struct sembuf sops[2];
    int semid;

    sops[0].sem_num = 0;        /* Operate on semaphore 0 */
    sops[0].sem_op = 0;         /* Wait for value to equal 0 */
    sops[0].sem_flg = 0;

    sops[1].sem_num = 0;        /* Operate on semaphore 0 */
    sops[1].sem_op = 1;         /* Increment value by one */
    sops[1].sem_flg = 0;


    /* create SHM segment */
    shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
    if (shmgetrc < 0) {
        perror("shmget failed...");
        exit(1);
    }
    /* retrieve the address of the segment */
    shared_values = (int *) shmat(shmgetrc, NULL, 0);

    /* create a semaphore */
    semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
    if (semgetrc < 0) {
        perror("semget failed...");
        exit(1);
    }

    /* lock the semaphore */
    if (semop(semgetrc, sops, 2) == -1) {
        perror("semop lock failed ...");
        exit(1);
    }

    /* fill it with values */
    for (i = 0; i < NUM_INTS; ++i) {
        shared_values[i] = i;
    }

    /* unlock the semaphore */
    sops[0].sem_op = -1;
    if (semop(semgetrc, sops, 1) == -1) {
        perror("semop release failed ...");
        exit(1);
    }

    /* here something else could happen */
    sleep(60);

    /* lock the semaphore */
    sops[0].sem_op = 0;
    if (semop(semgetrc, sops, 2) == -1) {
        perror("semop lock failed ...");
        exit(1);
    }

    /* print values */
    for (i = 0; i < NUM_INTS; ++i) {
        printf("%d ", shared_values[i]);
    }
    printf("\n");

    /* unlock the semaphore */
    sops[0].sem_op = -1;
    if (semop(semgetrc, sops, 1) == -1) {
        perror("semop release failed ...");
        exit(1);
    }

    /* remove the semaphore */
    if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
        perror("semctl failed ...");
        exit(1);
    }

    /* remove shm segment again */
    if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
        perror("shmctl failed ...");
        exit(1);
    }
    exit(0);
}

It was not my intention to write the most beautiful code ever written, just an example that shows:

  • how to create a shm segment
  • how to retrieve the address and to use it
  • how to remove it

Additionally, I've used a semaphore to protect the access.

Contrary to the other answer, I've used the ipc interface, not mmap().

Ronald
  • 2,842
  • 16
  • 16