为什么我在 c 中的矩阵乘法代码总是给出垃圾值? (使用共享内存和fork)

Why my Matrix Multipication code in c always give the garbage value? (using shared memory and fork)

这是我在 c 中的代码,用于执行矩阵乘法实现分叉和共享内存。看起来我得到的价值大部分是垃圾价值。也许我没有首先初始化作为结果数组的数组 C 的值。 (我是C初学者,第一次使用共享内存)

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define N 3

void doMulT(int row,int col,int x ,int a[][N],int b[][N],int c[]);
int main()
{
    int Ma[N][N];
    int Mb[N][N];
    int segment_id;
    pid_t pid=-1;

        printf("Input the elements in Matrix A (%dx%d) : \n",N,N);
        for(int k = 0; k<N ;k++)
        {
                for(int d = 0; d<N ; d++)
                {
                        scanf("%d",&Ma[k][d]);
                }
        }
        printf("Input the elements in Matrix B (%dx%d) : \n",N,N);
        for(int k = 0; k<N ;k++)
        {
                for(int d = 0; d<N ; d++)
                {
                        scanf("%d",&Mb[k][d]);
                }
        }

    segment_id = shmget(IPC_PRIVATE,1024, S_IRUSR|S_IWUSR);
        int *C = (int*)shmat(segment_id,NULL,0);

    for(int i=0;i<N*N;i++)
    {
        if(pid != 0)
        {
            pid = fork();
        }
    }

    if(pid == 0)
    {
        for(int i = 0; i<N; i++)
        {
            for(int j =0; i<N; j++)
            {
                if(C[i*N+j]==0)
                {
                    doMulT(i,j,N,Ma,Mb,C);
                }
            }
        }
    }

    else
    {
        for(int k =0;k<N*N;k++)
        {
            wait(NULL);
        }
        printf("==========Result==========\n");
            for(int i=0; i<N; i++)
            {
                    for(int j=0; j<N; j++)
                    {
                            printf("%d",C[i*N+j]);
                            printf(" ");
                    }
                    printf("\n");
            }
        }
    shmdt(C);
        shmctl(segment_id, IPC_RMID, NULL);
}

void doMulT(int row,int col,int x ,int a[][N],int b[][N],int c[])
{
        for(int k=0; k<x; k++)
        {
             c[row*x+col]+=a[row][k]*b[k][col];
        }
}

输入示例

Input the elements in Matrix A (3x3) :
1 1 1
2 2 2
3 3 3
Input the elements in Matrix B (3x3) :
1 1 1
2 2 2
3 3 3

输出就像

6 6 6
123482868 -745374 -2637821
456729394 -98475839 -2884829

本回答的第一部分旨在展示原始程序中的问题以及调试问题的方法。

我添加了一些 printf 输出以查看进程将做什么

    if(pid == 0)
    {
        for(int i = 0; i<N; i++)
        {
            for(int j =0; i<N; j++)
            {
                if(C[i*N+j]==0)
                {
                    printf("process %ld calculating (%d, %d)\n", (long)getpid(), i, j);
                    doMulT(i,j,N,Ma,Mb,C);
                }
            }
        }
    }

并得到这样的输出:

process 747 calculating (0, 204)                                                                                                                                                               
process 746 calculating (0, 292)                                                                                                                                                               
process 746 calculating (0, 293)                                                                                                                                                               
process 747 calculating (0, 205)                                                                                                                                                               
process 746 calculating (0, 294)                                                                                                                                                               
process 747 calculating (0, 206)                                                                                                                                                               
process 746 calculating (0, 295)                                                                                                                                                               
process 747 calculating (0, 207)                                                                                                                                                               

这意味着 j 的循环是错误的。

有错别字:

            for(int j =0; i<N; j++)

必须是

            for(int j =0; j<N; j++) // j<N  instead of  i<N

另外我用memset用0初始化共享内存。

修复循环后我得到

process 238 calculating (0, 0)                                                                                                                                                              
process 238 calculating (0, 1)                                                                                                                                                              
process 238 calculating (0, 2)                                                                                                                                                              
process 238 calculating (1, 0)                                                                                                                                                              
process 238 calculating (1, 1)                                                                                                                                                              
process 238 calculating (1, 2)                                                                                                                                                              
process 238 calculating (2, 0)                                                                                                                                                              
process 238 calculating (2, 1)                                                                                                                                                              
process 238 calculating (2, 2)                                                                                                                                                              
==========Result==========                                                                                                                                                                  
6 6 6                                                                                                                                                                                       
12 12 12                                                                                                                                                                                    
18 18 18                                                                                                                                                                                    

这意味着一个人 child 在其他人活跃之前完成了所有工作。

处理循环中的延迟让其他进程有机会完成一些工作。

注意:这并不是真正的解决方案。主要目的是表明不能依赖系统来分配进程之间的工作。

它还表明矩阵乘法不是多处理的好用例,因为矩阵单元的计算(至少对于您示例中的小矩阵)显然比创建新进程快得多.

    if(pid == 0)
    {
        for(int i = 0; i<N; i++)
        {
            for(int j =0; j<N; j++)
            {
                if(C[i*N+j]==0)
                {
                    printf("process %ld calculating (%d, %d)\n", (long)getpid(), i, j);
                    doMulT(i,j,N,Ma,Mb,C);
                    sleep(1); // give other processes a chance to do some work
                }
            }
        }
    }

要获得好的解决方案,您必须实施一种方法来为每个 child 进程分配特定任务。一种选择是将循环变量 i(或者可能是行和列的两个单独的循环变量)传递给 child 过程中的处理函数,如以下版本所示。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <memory.h>
#include <errno.h>
#include <stdlib.h>

#define N 3
#define SIZE 1024

void doMulT(int row,int col,int x ,int a[][N],int b[][N],int c[]);
int main()
{
    int Ma[N][N] = {
        {1, 1, 1},
        {2, 2, 2},
        {3, 3, 3}
    };
    int Mb[N][N] = {
        {1, 1, 1},
        {2, 2, 2},
        {3, 3, 3}
    };
    int segment_id;
    pid_t pid=-1;

#if 0
        printf("Input the elements in Matrix A (%dx%d) : \n",N,N);
        for(int k = 0; k<N ;k++)
        {
                for(int d = 0; d<N ; d++)
                {
                        scanf("%d",&Ma[k][d]);
                }
        }
        printf("Input the elements in Matrix B (%dx%d) : \n",N,N);
        for(int k = 0; k<N ;k++)
        {
                for(int d = 0; d<N ; d++)
                {
                        scanf("%d",&Mb[k][d]);
                }
        }
#endif

    segment_id = shmget(IPC_PRIVATE, SIZE, S_IRUSR|S_IWUSR);
        int *C = (int*)shmat(segment_id,NULL,0);

    memset(C, 0, SIZE);
    
    for(int i=0; (pid != 0) && (i<N); i++)
    {
        for(int j=0; (pid != 0) && (j<N); j++)
        {
            if(pid != 0)
            {
                pid = fork();
                if(pid == 0)
                {
                    printf("process %ld calculating (%d, %d)\n", (long)getpid(), i, j);
                    doMulT(i,j,N,Ma,Mb,C);
                    exit(0);
                }
            }
        }
    }


    if(pid != 0)
    {
        while(wait(NULL) != -1 || (errno != ECHILD))
        {
            ;
        }
        printf("==========Result==========\n");
            for(int i=0; i<N; i++)
            {
                    for(int j=0; j<N; j++)
                    {
                            printf("%d",C[i*N+j]);
                            printf(" ");
                    }
                    printf("\n");
            }
        }
    shmdt(C);
        shmctl(segment_id, IPC_RMID, NULL);
}

void doMulT(int row,int col,int x ,int a[][N],int b[][N],int c[])
{
        for(int k=0; k<x; k++)
        {
             c[row*x+col]+=a[row][k]*b[k][col];
        }
}

输出如下所示:

process 7489 calculating (0, 0)                                                                                                                                                             
process 7495 calculating (2, 0)                                                                                                                                                             
process 7496 calculating (2, 1)                                                                                                                                                             
process 7497 calculating (2, 2)                                                                                                                                                             
process 7493 calculating (1, 1)                                                                                                                                                             
process 7490 calculating (0, 1)                                                                                                                                                             
process 7494 calculating (1, 2)                                                                                                                                                             
process 7492 calculating (1, 0)                                                                                                                                                             
process 7491 calculating (0, 2)                                                                                                                                                             
==========Result==========                                                                                                                                                                  
6 6 6                                                                                                                                                                                       
12 12 12                                                                                                                                                                                    
18 18 18