1

我有一个任务是从命令行获取一个字符串,将其反转并使用 fork() 在单独的子进程中输出每个字符。我只是没有从 fork() 调用中获得正确的输出。问题是索引在输出时会变得混乱,比如 3, 1, 2, 0 当它应该只是 3,2,1,0 ......等等......更令人困惑的是它随机成功时word 长度为 3 个字符(但并非总是如此),但通常对于 4 个以上字符的单词是不正确的。在没有 fork() 调用的情况下,循环可以正常工作。

这是我的主要功能,问题存在于for循环中。

int main(int argc, char **argv){
    pid_t childpid = 0;
    int i;
    char* invert = new char[strlen(argv[1])+1];
    int invert_length = strlen(argv[1]);
    strcpy(invert, argv[1]);
    for(i=invert_length-1; i>=0; i--){
        childpid = fork();
        if(childpid==(pid_t) 0){
            //I am the child            
            cout<<"Child ["<< i <<"] = "  << invert[i] <<"."<<endl;
            break;
        }
    }   
    return 0;
}
4

4 回答 4

2

对您的程序进行简单修改即可使其工作。让孩子做下一个叉子。每个进程都等待它产生的那个。

int main(int argc, char **argv){
    pid_t childpid = 0;
    int i;
    char* invert = new char[strlen(argv[1])+1];
    int invert_length = strlen(argv[1]);
    strcpy(invert, argv[1]);
    for(i=invert_length-1; i>=0; i--){
        childpid = fork();
        if(childpid==(pid_t) 0){
            //I am the child
            cout<<"Child ["<< i <<"] = "  << invert[i] <<"."<<endl;
            continue;
        }
        break;
    }
    wait(0);
    return 0;
}

编辑: Skizz 反对每个进程在启动下一个进程之前执行其工作。问题中没有要求首先启动所有进程,但下面的版本会这样做。

int main(int argc, char **argv){
    pid_t childpid = 0;
    int i;
    char* invert = new char[strlen(argv[1])+1];
    int invert_length = strlen(argv[1]);
    strcpy(invert, argv[1]);
    for(i=0; i<invert_length; ++i){
        childpid = fork();
        if(childpid!=(pid_t) 0){
            wait(0);
            break;
        }
    }
    if (i-->0) cout<<"Child ["<< i <<"] = "  << invert[i] <<"." <<endl;
    return 0;
}
于 2012-07-11T10:53:20.713 回答
0

问题是 fork 调用产生了一个新进程,复制了调用进程。当您在循环中执行此操作时,您现在有很多进程都希望同时执行。它们执行的顺序(因为 CPU 一次只能执行一个进程*)取决于操作系统,因为这是选择执行哪个进程的东西,因此输出变得不确定。

为了解决这个问题,每个生成的进程都需要知道何时输出,这意味着在进程之间使用某种同步。

笔记:

  • 为简单起见,我忽略了超线程/多核。
于 2012-07-11T10:39:46.840 回答
0

编辑:

您可以分叉,然后调用wait,从而满足硬件要求。我在下面的原始答案是如何在更复杂的环境(真正的应用程序)中运行它,以及如何利用在单独的进程中运行一些代码

wait如上所述添加

int main(int argc, char **argv){
    pid_t childpid = 0;
    int i;
    char* invert = new char[strlen(argv[1])+1];
    int invert_length = strlen(argv[1]);
    strcpy(invert, argv[1]);
    for(i=invert_length-1; i>=0; i--){
        childpid = fork();
        if(childpid==(pid_t) 0){
            //I am the child            
            cout<<"Child ["<< i <<"] = "  << invert[i] <<"."<<endl;
            break;
        }
        else {
          int stat;
              wait(&stat);
        }
    }   
    return 0;
}

我同意@illusionoflife,但如果它的功课那么它一定是可能的

您可以为 SIGCHLD 设置一个事件处理程序(例如使用 libevent),然后在收到第一个 SIGGCHLD 等后启动下一个子进程

本练习的重点可能不是跨多个 CPU 的负载平衡,而是展示您可以使用Copy On Write执行的操作。

是我几个月前问的一个问题,让你开始

于 2012-07-11T10:40:28.793 回答
0

情况与 pthread 相同。不保证,孩子将按生成顺序执行。注意 SIGCHLD。

于 2012-07-11T10:34:35.940 回答