创建一个 fork 导致 fgets 无限地重读文件

问题描述 投票:0回答:1

我正在尝试编写一个程序来读取一堆unix命令,并创建子进程来执行它们。它有一个参数决定我想要同时运行的子进程的最大数量。我将

stdin
重定向到一个包含如下命令的单独文件:
./a.out 3 < batchcmds
。当我运行代码时,它最终会一遍又一遍地重新读取所有命令,但是当我注释掉 switch 语句时,它会按预期运行(当然,创建进程和运行命令除外)。我通过测试确认所有子进程在到达 while 循环结束之前都会终止,因此主进程一定以某种方式被搞乱了,导致它重复读取文件。这是我的代码:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int makearg(char*, char***);

#define BUFFERSIZE 1024

int main(int argc, char** argv) {
        // reads argument
        int maxpc = atoi(argv[1]);
        int pc = 0;

        // read from the file and assign it to a child
        char command[BUFFERSIZE];
        while(fgets(command, 128, stdin) > 0) {
                char** args;
                makearg(command, &args);

                if(pc >= maxpc) {
                        wait(NULL);
                        pc--;
                }

                switch(fork()) {   // When I comment out from here to the comment below it works as expected
                        case 0:
                                // is child
                                execvp(args[0], args);
                                printf("execv failed to run %s", command);
                                exit(0);
                                printf("child is immortal\n");
                                return -1;
                        case -1:
                                printf("failed to create child\n");
                                break;
                        default:
                                // is parent
                                pc++;
                }  // The comment below
                printf("end while loop: %x:%s", getpid(), command);
        }

        // wait for children to finish
        for(; pc > 0; pc--) wait(NULL);

        return 0;
}

int makearg(char* s, char*** args) {
        // count the tokens in the string
        int tokencount = 1;
        int slength = 1;
        for(char* c = s; *c != '\0'; c++) {
                if(*c == ' ')
                        tokencount++;
                slength++;
        }

        // set up the array of tokens
        char** tokens = (char**)malloc(tokencount*sizeof(char*));
        if(tokens == NULL) {
                return -1;
        }
        for(int i = 0; i < tokencount; i++)
                tokens[i] = (char*)malloc(slength*sizeof(char));
        if(tokens == NULL) {
                for(int i = 0; i < tokencount; i++)
                        free(tokens[i]);
                free(tokens);
                return -1;
        }

        // copy data over to the token array
        int itoken = 0;
        int ichar = 0;
        for(char* c = s; *c != '\0'; c++) {
                if(*c == ' ') {
                        tokens[itoken][ichar] = '\0';
                        itoken++;
                        ichar = 0;
                }
                else if(*c != '\n') {
                        tokens[itoken][ichar] = *c;
                        ichar++;
                }
        }
        tokens[itoken][ichar] = '\0';

        *args = tokens;
        return tokencount;
}

这真的把我难住了,我找不到有类似问题的人。任何帮助将不胜感激!

c process io
1个回答
0
投票

问题在于标准输入/标准输出的共享...请记住,fork 几乎复制了所有内容,并且共享输入/输出确实是一团糟。 最好是确保根本没有缓冲,以便对输入/输出 C 函数的任何调用都将直接从操作系统层获取/放置。 添加:

setvbuf(stdin,NULL,_IONBF,0);
setvbuf(stdout,NULL,_IONBF,0);

循环之前。

© www.soinside.com 2019 - 2024. All rights reserved.