1

I have a project to illustrate how to use shared memory in C. And this is my suggested assignment for my project this semester: adding up all elements in a 2d array, in a special way:

  • take input from user the row size (m) and column size (n), for example m = 4, n = 3.
  • the program will be called, for example: myadder 9 8 7 3 2 1 2 3 4 2 10 12 (these 12 numbers input are separated by white-space or return key)
  • create a shared memory 1d array of enough size to hold the entire above 2d array
  • then, create a shared memory 1d array of the size of the number of rows m. This array will be used to store the totals of each of the rows after it is calculated
  • the program then fork off a child process for each row in the array. This child process will total up its associated row and only it's row from shared memory, and store result in its associated element in another 1d array, called total_row
  • The parent process will wait until all children have finished, then add up all elements in total_row.

Can you give me hints to finish the above task?

4
  • what would the calls to malloc look like? Commented Aug 6, 2013 at 4:00
  • How would you index through the large malloc using m and n? Commented Aug 6, 2013 at 4:00
  • Use shm* family to get and control the shared memory and semaphores to synchronize. Read manuals and check here cs.cf.ac.uk/Dave/C/node27.html Commented Aug 6, 2013 at 4:02
  • Take little bites; for example, write a program to read the sizes and the values, and correctly create the array. Then write the code to sum up a row. Then fork a child and let the child sum a row. Finally, fork off a child for each row, wait for the children to finish, then add it up. Commented Aug 6, 2013 at 4:03

3 Answers 3

1

I believe this should do the trick:

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

int main ()
{
    int w, h, i, j;

    /* Read the width and height */
    scanf ("%d %d", &w, &h);

    /* Create and read the entire array */
    int *arr = malloc (w * h * sizeof (int));
    for (i = 0; i < w * h; ++i)
        scanf ("%d", &arr[i]);

    /* Obtain a shared memory segment with the key 42 */
    int shm = shmget (42, h * sizeof (int), IPC_CREAT | 0666);
    if (shm < 0)
    {
        perror ("shmget");
        return 1;
    }

    /* Attach the segment as an int array */
    int *row = shmat (shm, NULL, 0);
    if (row < (int *) NULL)
    {
        perror ("shmat");
        return 1;
    }

    for (i = 0; i < h; ++i)
        /* Create h children and make them work */
        if (!fork ())
        {
            for (j = row[i] = 0; j < w; ++j)
                row[i] += arr[i * w + j];
            return 0;
        }

    /* Wait for the children to finish up */
    for (i = 0; i < h; ++i)
        wait (&j);

    /* Sum the row totals */
    for (i = j = 0; i < h; ++i)
        j += row[i];

    printf ("%d\n", j);

    /* Detach the shared memory segment and delete its key for later reuse */
    shmdt (row);
    shmctl (shm, IPC_RMID, NULL);

    free (arr);
    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

The question seems to call for two shared memory segments, one to hold the array and one to hold the row sums. Your malloc'd array needs to be a shared memory segment instead. Otherwise, it is pretty much on track, for all it's a little scanty on error detection and reporting. Of course, you can't use 'The Answer' (to 'The Question of Life, the Universe, and Everything') as the key for two separate shared memory segments.
You are correct, but I am relying on the copy-on-write implementation of fork() to keep the array virtually "shared" for reading. I suppose that, and the error reporting, and picking a new key, are left as exercises to the reader :)
1

Consider the following array declaration:

int arr[8];

What happens in memory when we make this declaration?

32 bytes are immediately reserved in memory, 4 bytes each for the 8 integers. Since the array is not being initialized, all 8 values present in it would be garbage values.

This happens because the storage class of this array is assumed to be AUTO. If the storage class is declared to be STATIC, then all of the array elements would have a default initial value of 0.

Whatever be the initial values, all of the array elements would always be present in contiguous memory locations.

This arrangement of array elements in memory is shown in fig.

  12        34        66      -45        23         346         77           90
 65508     65512     65516    65520     65524       65528      65532        65536 

Comments

0

This below code uses 2 shared memory segments..

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

    #define KEY_2D  12345
    #define KEY_ROW 54321

    int main(int argc, char **argv) {

            int rows, cols; 

            scanf("%d %d", &rows, &cols);
            if(rows <= 0 || cols <= 0) {
                    printf("invalid input\n");
                    return 1;
            }

            int *dataa_user = NULL; /* To get user input for 2D array */
            int i = 0; 
            int shm_2d = -1;

            dataa_user = (int *) malloc(rows * cols * sizeof(int));
            /* Do you need to take input from user as 2D array? and then 
             * convert it back to 1D array? 
             * I wonder as this is probably your assignment to understand
             * some C and Unix concepts
             */     
            for(i = 0; i < rows * cols; i ++)
                    scanf("%d", &dataa_user[i]);

            /* Creating shared memory that holds 2D array as 1D array */
            shm_2d = shmget(KEY_2D, rows * cols * sizeof (int), IPC_CREAT | 0666);

            if(shm_2d < 0) {
                    perror("shmget");
                    if(dataa_user) free(dataa_user);
                    dataa_user = NULL; 
                    return 1;
            }

            /* Attach to the shared memory */
            void *data_2d = shmat(shm_2d, NULL, 0);
            if(data_2d == (void *)-1) {
                    perror("shmat");
                    shmctl (shm_2d, IPC_RMID, NULL);
                    if(dataa_user) free(dataa_user);
                    dataa_user = NULL;
                    return 1;
            }

            int shm_row = -1;
            /* Copy the 1D array to shared memory */
            memcpy( data_2d, dataa_user, rows * cols * sizeof(int));
            free(dataa_user);
            dataa_user = NULL;
            /* Creating shared memory to keep the sum of each row as 1D array */
            shm_row = shmget(KEY_ROW, rows * sizeof (int), IPC_CREAT | 0666);

            if(shm_row < 0) {
                    perror("shmget");
                    shmdt(data_2d);
                    shmctl (shm_2d, IPC_RMID, NULL);
                    return 1;
            }   /* this closing brace was missed when i posted it first time.. */

            /* Attach to the shared memory */
            void *data_row = shmat(shm_row, NULL, 0);
            if(data_row == (void *)-1) {
                    perror("shmat");
                    shmdt (data_2d);
                    shmctl (shm_2d, IPC_RMID, NULL);
                    shmctl (shm_row, IPC_RMID, NULL);
                    return 1;
            }
            /* Initialize it to 0. */
            memset(data_row, 0, rows * sizeof(int));

            for(i = 0; i < rows; i ++) {
                    if(!fork()) {
                            int k = 0;
                            int *dataa_2d = (int *)data_2d;
                            int *total_row = (int *)data_row;
                            for(; k < cols; k ++)
                                    total_row[i] += dataa_2d[i * cols + k]; //add data to shm[row index] for each col in that row
                            return 0;
                    }
            }

            int sts = 0;
            for(i = 0; i < rows; i ++) {
                    wait(&sts);     /* wait for all the children to exit. */
            }

            int total_2d = 0;
            int *total_row = (int *)data_row;
            for(i = 0; i < rows; i ++) {
                    total_2d += total_row[i];       /* main process adding up all the row sum values */
            }

            printf("%d\n", total_2d);

            /* clean up of IPC(shms used) */
            shmdt(data_2d);
            shmdt(data_row);

            shmctl (shm_2d, IPC_RMID, NULL);
            shmctl (shm_row, IPC_RMID, NULL);

            return 0;
    }

Your problem statement only mandates use of fork() system call.. So, the problem as such is simple (taking advantage of COW)..

(If you were supposed to use exec() system calls, then it might help you understand the reality in linux systems.. Also if totalling of total_row was assigned to each child process, like summing up to 3rd shared memory or something, it would have helped in understanding synchronization.. )

Anyway, hope this helps..

1 Comment

Sure.. Btw, there was a paste mistake that I had missed to paste one line which had a closing brace for one of the if conditions.. Plz recheck if you haven't already figured it out..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.