利用无名管道实现简单并行计算

名称:利用无名管道实现简单并行计算
说明:本程序利用无名管道进行进程间通信,达到多进程同时计算的目的。
基本算法是:首先在主进程里创建了一定数量的子进程,然后主进程通过无名管道向子进程传递要计算的数据,子进程计算后,通过无名管道将计算的结果(此处是求和)返回给主进程,主进程进行汇总。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <malloc.h>
#include <time.h> 
#define READ_END 0
#define WRITE_END 1
#define PRO_NUM     4       //进程数量
#define DATA_NUM    100     //数据数量
#define NUM (DATA_NUM / DATA_NUM)   //每个进程所要处理的数据个数;

//#define   NUM (PRO_NUM)/(DATA_NUM)        //运行结果有错误
#define NUM 100 / 4
typedef struct
{
    int main_to_sub_fd[2];      //信息流从主进程流向子进程,管道读写描述符(即主进程向子进程传递数据)    
    int sub_to_main_fd[2];      //信息流从子进程流向主进程,管道读写描述符(即子进程将计算的结果返回给主进程)    

}FD_table;


FD_table  fdtable[PRO_NUM]; 

//创造模拟的随机数数据,此处的种子是进程序号
void create_rand(int ** data,int ran)
{
    int i = 0;
    *data = (int *)malloc(sizeof(int) * NUM);   //申请数据空间

    srand(ran);  
    for(;i<NUM;++i)
    {
        (*data)[i] = rand() % 100 + 1;      //产生100以内的随机数

    }

}


//产生管道表,用于主进程查询用
int create_pipe_table()
{
    int i = 0;
    for(;i<PRO_NUM;++i)
    {

        if(-1 == pipe(fdtable[i].main_to_sub_fd))   //创造管道
        {
            printf("pipe failed.\n");
            return 1;
        }

        if(-1 == pipe(fdtable[i].sub_to_main_fd))   //创造管道
        {
            printf("pipe failed.\n");
            return 1;
        }

    }

    return 0;

}

//每个子进程求和
int cal(int data[])
{
    int i = 0;
    int sum = 0;
    for(;i<NUM;++i)
    {
        sum = sum + data[i];
    }

    return sum;
}

//子进程的所有操作
void child_pro(int data[],int flag)
{
    int sum = 0;

    int i = 0;

    read((fdtable[flag]).main_to_sub_fd[READ_END],data,sizeof(int)*NUM);    //子进程从主进程的管道中读取数据


    sum = cal(data);        //每个子进程计算求和

    printf("(%d):the sum is %d\n",getpid(),sum);

    write(fdtable[flag].sub_to_main_fd[WRITE_END],&sum,sizeof(int));    //子进程计算结果写入到主进程
}

int main()
{
    int temp  = 0;
    pid_t pid;
    int i = 0;
    int flag = 0;   //用来识别进程的编号

    int sums[PRO_NUM];
    int total_sum = 0;
    int *_data = NULL;  //用于主进程产生随机数,并传给子进程
    memset(sums,0,sizeof(int)*PRO_NUM);
    int data[NUM];      //用于存储子进程从主进程接收到的数据
    memset(data,0,sizeof(int)*NUM);
    create_pipe_table(fdtable);     
    while(1)
    {
        //每次循环创建进程
        pid = fork();   
        if(pid > 0 )        //父进程
        {
            if( i >= PRO_NUM - 1 )
            {
                for(i = 0;i<PRO_NUM;++i)
                {

                    create_rand(&_data,i);

                    write(fdtable[i].main_to_sub_fd[WRITE_END],_data,sizeof(int)*NUM);  //向管道中写入随机数

                }

                for(i = 0;i<PRO_NUM;++i)
                {
                    read(fdtable[i].sub_to_main_fd[READ_END],&sums[i],sizeof(int)); //从子进程管道中读出数据

                    total_sum = total_sum + sums[i];
                }

                printf("The total sum is %d\n",total_sum);

                //主进程结束,在此等待
                while(1)
                {
                    printf("the parent process is waiting ....\n");
                    sleep(3);
                };


            }

        }
        else        //子进程
        {
            printf("this is the %d process.\n",i);
            flag = i;
            break;
        }

        ++i;

    }

    //子进程执行
    child_pro(data,flag);
    return 0;
}

总结:这个程序写了好久,一开始有个问题一直得不到解决。就是主进程接受到的结果老是不正确,总是其发送给子进程的第一个数据。而子进程接收到的数据,也是从主进程发送的第二个数据开始的。
折腾了好几天,终于弄清楚了。还是对于管道没理解清楚。每创建一个管道,就会产生两个描述符,只要得到了这两个描述符,就能从相应的管口进行读写。本程序原来对于每个程序只维护了一个管道,本来想的是,主进程向这个管道写入原始数据,子进程从这个管道中读入原始数据。子进程计算后,将结果在通过这个管道写入,然后主进程将结果读出。感觉是没什么问题,但是看程序就知道,主进程在向每个子进程写入数据后,就一直轮循向管道中读入数据,这个时候如果子进程还没将结果写入管道,那么主进程读入的结果就是错误的。(原来犯得错误就是主进程读的数据是自己原来写入的第一个数据)。我去,扯了这么多,突然想到可以用一句话代替啊,就是管道是半双工通信的。傻了我。
找到了错误原因,改起来就方便了,对每个子进程和主进程之间的通信又加了一对管道,即使用两组管道就可以了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值