使用C语言中的fork和pipe函数来计算具有多个进程的文件中的行,字符和单词

如何解决使用C语言中的fork和pipe函数来计算具有多个进程的文件中的行,字符和单词

我正在尝试使用带有fork和pipe函数的多个进程来修改一个程序,该程序读取文件并返回行,单词和字符的总数。该程序可以编译并正常运行,但是当前仅当用户为子进程数输入1时,输出才正确。对于每隔一个正整数,程序将返回正确的值乘以进程数。 (例如:如果文件中的行数为4,而用户输入的进程数为2,则返回值为8)有谁知道我可以解决这个问题,以便每个进程将读取文件的工作而不是每次读取的工作分摊通过整个事情?用户在运行程序时输入文件名和所需的子进程数。我目前不关心效率,只是输出正确。这是我的代码:

//wc.h
#ifndef WC_H
#define WC_H

#include <stdio.h>

typedef struct count_t {
        int linecount;
        int wordcount;
        int charcount;
} count_t;

count_t word_count(FILE* fp,long offset,long size);
extern int crashRate;

#endif



//wc_mul.c
#include "wc.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

#define MAX_PROC 100
#define MAX_FORK 100

int crashRate = 0;

count_t word_count(FILE* fp,long size)
{
        char ch;
        long rbytes = 0;

        count_t count;
        // Initialize counter variables
        count.linecount = 0;
        count.wordcount = 0;
        count.charcount = 0;
        
        printf("[pid %d] reading %ld bytes from offset %ld\n",getpid(),size,offset);

        if(fseek(fp,offset,SEEK_SET) < 0) {
                printf("[pid %d] fseek error!\n",getpid());
        }

        while ((ch=getc(fp)) != EOF && rbytes < size) {
                // Increment character count if NOT new line or space
                if (ch != ' ' && ch != '\n') { ++count.charcount; }

                // Increment word count if new line or space character
                if (ch == ' ' || ch == '\n') { ++count.wordcount; }

                // Increment line count if new line character
                if (ch == '\n') { ++count.linecount; }
                rbytes++;
        }

        srand(getpid());
        if(crashRate > 0 && (rand()%100 < crashRate)) 
        {
                printf("[pid %d] crashed.\n",getpid());
                abort();
        }

        return count;
}


int main(int argc,char **argv)
{
                long fsize;
                FILE *fp;
                int numJobs;
        //plist_t plist[MAX_PROC];
                count_t total,count,buf;
                int i,j,pid,status,p[2];
                int nFork = 0;

        if(argc < 3) {
                printf("usage: wc <# of processes> <filname>\n");
                return 0;
        }
        
        if(argc > 3) {
                crashRate = atoi(argv[3]);
                if(crashRate < 0) crashRate = 0;
                if(crashRate > 50) crashRate = 50;
        }
        printf("crashRate RATE: %d\n",crashRate);


        numJobs = atoi(argv[1]);
        if(numJobs > MAX_PROC) numJobs = MAX_PROC;

        total.linecount = 0;
        total.wordcount = 0;
        total.charcount = 0;

        // Open file in read-only mode
        fp = fopen(argv[2],"r");

        if(fp == NULL) {
                printf("File open error: %s\n",argv[2]);
                printf("usage: wc <# of processes> <filname>\n");
                return 0;
        }

        fseek(fp,0L,SEEK_END);
        fsize = ftell(fp);
        
        fclose(fp);
        // calculate file offset and size to read for each child
        
        for(i = 0; i < numJobs; i++) {
                if(nFork++ > MAX_FORK) return 0;
                if (pipe(p) != 0)
                  exit(1);
                pid = fork();
                if(pid < 0) {
                        printf("Fork failed.\n");
                } else if(pid == 0) {
                        // Child
                        fp = fopen(argv[2],"r");           
                        count = word_count(fp,fsize);
                        write(p[1],&count,sizeof(count));
                        close(p[0]);
                        close(p[1]);
                        // send the result to the parent through the message queue
                        fclose(fp);
                        return 0;
                }
        }
        waitpid(pid,&status,0);
        close(p[1]);
        for (j=0; j < numJobs; j++) {
          read(p[0],&buf,sizeof(count));
          total.linecount += buf.linecount;
          total.wordcount += buf.wordcount;
          total.charcount += buf.charcount;
        }
        // Parent
        // wait for all children
        // check their exit status
        // read the result from normalliy terminated child
        // re-crete new child if there is one or more failed child
        
        printf("\n========== Final Results ================\n");
        printf("Total Lines : %d \n",total.linecount);
        printf("Total Words : %d \n",total.wordcount);
        printf("Total Characters : %d \n",total.charcount);
        printf("=========================================\n");
        return(0);
}

解决方法

  1. 必须{strong>在之前打开pipe。否则,它在父级中不可用。

  2. 指针传递给count而不是count本身,传递给readwrite

write(p[1],&count,sizeof(count)); .. read(p[0],&buf,sizeof(count));

  1. 每个孩子都需要在write之后通过close(p[1])关闭管道的写入端。现在,您只需要关闭读取端即可。

PS:建议对readwrite添加通常的结果检查。


如果您将单个pipe用于多个进程,则第一个孩子关闭pipe后,它将关闭并且无法再读取。

您需要一组管道,每个进程一个:

int p[numJobs][2];

以下代码对我有用。我添加了一些printf以便更好地理解。

int main(int argc,char **argv)
{
    long fsize;
    FILE *fp;
    int numJobs;

    count_t total,count,buf;
    int i,j,pid,status;

    if(argc < 3) {
            printf("usage: wc <# of processes> <filname>\n");
            return 0;
    }
        
    if(argc > 3) {
            crashRate = atoi(argv[3]);
            if(crashRate < 0) crashRate = 0;
            if(crashRate > 50) crashRate = 50;
    }
    printf("crashRate RATE: %d\n",crashRate);


    numJobs = atoi(argv[1]);
    if(numJobs > MAX_PROC) numJobs = MAX_PROC;

    int p[numJobs][2];
    
    total.linecount = 0;
    total.wordcount = 0;
    total.charcount = 0;

    // Open file in read-only mode
    fp = fopen(argv[2],"r");

    if(fp == NULL) {
            printf("File open error: %s\n",argv[2]);
            printf("usage: wc <# of processes> <filname>\n");
            return 0;
    }

    fseek(fp,0L,SEEK_END);
    fsize = ftell(fp);
    
    fclose(fp);
        // calculate file offset and size to read for each child
        
    for(i = 0; i < numJobs; i++) {
        
        if (pipe(p[i]) != 0) exit(1);

        pid = fork();
        
        if(pid < 0) {
            printf("Fork failed.\n");
            exit(1);
        } else if(pid == 0) {
            
            // Child
            fp = fopen(argv[2],"r");
            count = word_count(fp,fsize);
            fclose(fp);

            close(p[i][0]);

            // send the result to the parent through the message queue
            long bytes_sent;
            
            if ( (bytes_sent = write(p[i][1],sizeof(count)) ) ==-1) {
                printf("Writing into pipe failed.\n");
                exit(1);
            };
            printf("Child  process %d sent %ld bytes (%'d lines,%'d words,%'d chars) \n",getpid(),bytes_sent,count.linecount,count.wordcount,count.charcount);
            
            close(p[i][1]);
            _exit(0);
            
        }
    }
    
    
    // wait for all child processes to close
    while(wait(NULL) != -1){};

    long bytes_read;
    
    for (j=0; j < numJobs; j++) {
                
        if ((bytes_read = read(p[j][0],sizeof(buf)) ) ==-1) {
            printf("Reading from pipe failed.\n");
            exit(1);
        };

        if (bytes_read){
            
            printf("Parent process %d read %ld bytes (%'d lines,bytes_read,buf.linecount,buf.wordcount,buf.charcount);

            total.linecount += buf.linecount;
            total.wordcount += buf.wordcount;
            total.charcount += buf.charcount;
        }
                    
        close(p[j][0]);
        close(p[j][1]);
    }


    // Parent
        // wait for all children
        // check their exit status
        // read the result from normalliy terminated child
        // re-create new child if there is one or more failed child
        
        printf("\n========== Final Results ================\n");
        printf("Total Lines : %d \n",total.linecount);
        printf("Total Words : %d \n",total.wordcount);
        printf("Total Characters : %d \n",total.charcount);
        printf("=========================================\n");
        return(0);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-