1

我有一个项目来说明如何在 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 数组中,称为 total_row
  • 父进程将等到所有子进程都完成后,然后将 total_row 中的所有元素相加。

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

4

3 回答 3

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;
}
于 2013-08-06T04:46:21.357 回答
1

考虑以下数组声明:

诠释 arr[8];

当我们做出这个声明时,内存中会发生什么?

32 个字节立即保留在内存中,8 个整数各占 4 个字节。由于该数组未初始化,因此其中存在的所有 8 个值都是垃圾值。

发生这种情况是因为该数组的存储类假定为 AUTO。如果存储类被声明为 STATIC,则所有数组元素的默认初始值都为 0。

无论初始值是什么,所有数组元素都将始终存在于连续的内存位置中。

存储器中数组元素的这种排列如图 1 所示。

  12        34        66      -45        23         346         77           90
 65508     65512     65516    65520     65524       65528      65532        65536 
于 2013-11-24T06:21:49.343 回答
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 的总计分配给每个子进程,例如汇总到第三个共享内存或其他内容,它会有助于理解同步..)

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

于 2013-08-06T10:03:26.467 回答