使用C中的共享内存添加数组的元素

时间:2013-08-06 03:56:05

标签: c unix memory fork shared

我有一个项目来说明如何在C中使用共享内存。这是我在本学期为我的项目建议的任务:以特殊方式将二维数组中的所有元素相加:

  
      
  • 从用户输入行大小(m)和列大小(n),例如m = 4,n = 3.
  •   
  • 将调用该程序,例如:myadder 9 8 7 3 2 1 2 3 4 2 10 12(这12个数字输入由空格或返回键分隔)
  •   
  • 创建一个足够大小的共享内存1d数组来容纳整个上面的2d数组
  •   
  • 然后,创建一个大小为m行的共享内存1d数组。此数组将用于存储计算后每行的总数
  •   
  • 程序然后为数组中的每一行分叉一个子进程。这个子进程将总计其关联的行,只有它来自共享内存的行,并将结果存储在另一个1d数组中的关联元素中,称为total_row
  •   
  • 父进程将等待所有子进程完成,然后将所有元素添加到total_row中。
  •   

你能给我提示完成上述任务吗?

3 个答案:

答案 0 :(得分:1)

我相信这应该可以解决问题:

#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;
}

答案 1 :(得分:1)

考虑以下数组声明:

int arr [8];

当我们做出此声明时,内存会发生什么? 32个字节立即保留在内存中,每个4个字节用于8个整数。由于数组未被初始化,因此其中存在的所有8个值都是垃圾值。这是因为 假定此数组的存储类为AUTO。如果存储类声明为STATIC,则所有数组元素的默认初始值都为0.无论是初始值,所有数组元素都将始终存在于连续的内存位置。 存储器中阵列元素的这种排列如图

所示

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

答案 2 :(得分:0)

以下代码使用2个共享内存段..

    #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;
    }

你的问题陈述只要求使用fork()系统调用..所以,这样的问题很简单(利用COW)..

(如果您应该使用exec()系统调用,那么它可能有助于您了解linux系统中的实际情况。此外,如果为每个子进程分配了total_row的总和,例如总计到第3个共享内存或者其他内容,它有助于理解同步..)

无论如何,希望这会有所帮助..