C++ 二进制在 UNIX 中分叉某些数字

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

我正在学习 fork 如何与类 Unix 操作系统一起工作。 我想创建 9 个子进程,每个父进程只能创建 2 个子进程。 所以这是一个二分叉算法。

但是我无法限制在第三次递归调用中创建的正确子级数量。

这是创建孩子的流程。

这是我现在拥有的代码。

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

using namespace std;

static int CHILD_SIZE = 9;
static int LEVEL = 1;
static int MAX_LEVEL = 3;

void createChildren(int remaining, int level) {

    int CURRENT_REMAINING = remaining;
    
    if(CURRENT_REMAINING <= 0 || level > MAX_LEVEL){
        return;
    }
    
    pid_t firstChild,secondChild;
    
    // Fork the first child
    firstChild = fork();
    
    if(firstChild == -1){
        cerr << "Fork failed!" << endl;
    }
    else if (firstChild == 0 && CURRENT_REMAINING > 1)
    {
        // first child
        cout << "First child process (PID: " << getpid() << ") with parent process (PID: " << getppid() << ") at level: " << level << endl;
        
        // calculate how many child needs after this iteration
        CURRENT_REMAINING -= (2 * level);
        if(CURRENT_REMAINING < 0){
            CURRENT_REMAINING = 0;
        }
    
    }
    else if (firstChild > 0 && CURRENT_REMAINING > 1)
    {
        // Fork the second child
        secondChild = fork();
    
        if(firstChild == -1){
            cerr << "Fork failed!" << endl;
        }
        else if (secondChild == 0) {
            // second child
            waitpid(firstChild, NULL, 0);
            cout << "Second child process (PID: " << getpid() << ") with parent process (PID: " << getppid() << ") at level: " << level << endl;
    
            // calculate how many child needs after this iteration
            CURRENT_REMAINING -= (2 * level);
            if(CURRENT_REMAINING < 0){
                CURRENT_REMAINING = 0;
            }
        } else if (secondChild > 0){
            // Wait for both child processes to complete
            waitpid(firstChild, NULL, 0);
            waitpid(secondChild, NULL, 0);
        }
    }
    
    
    //---------- recursion call-----------//
    
    //  upper child recursion call
    if(firstChild == 0){
    
        cout << "current remaining in first child is: " << CURRENT_REMAINING << " at level " << level << endl;
    
        createChildren(CURRENT_REMAINING, level + 1);
    }
    
    // lower child recursion call
    if(secondChild == 0){
    
        cout << "current remaining in second child is: " << CURRENT_REMAINING << " at level " << level << endl;
    
        if(CURRENT_REMAINING > 3){
            //cout << "Create two more processes" << endl;
            createChildren(CURRENT_REMAINING, level + 1);
        }
    }

}

int main() {

    std::cout << "Parent process " << getpid() << std::endl;
    createChildren(CHILD_SIZE, LEVEL);
    
    return 0;

}

这是输出:

Parent process 8571
First child process (PID: 8573) with parent process (PID: 8571) at level: 1
current remaining in first child is: 7 at level 1
Second child process (PID: 8574) with parent process (PID: 8571) at level: 1
current remaining in second child is: 7 at level 1
First child process (PID: 8575) with parent process (PID: 8573) at level: 2
current remaining in first child is: 3 at level 2
First child process (PID: 8576) with parent process (PID: 8574) at level: 2
current remaining in first child is: 3 at level 2
Second child process (PID: 8577) with parent process (PID: 8573) at level: 2
current remaining in second child is: 3 at level 2
Second child process (PID: 8578) with parent process (PID: 8574) at level: 2
current remaining in second child is: 3 at level 2
First child process (PID: 8579) with parent process (PID: 8575) at level: 3
current remaining in first child is: 0 at level 3
Second child process (PID: 8581) with parent process (PID: 8575) at level: 3
current remaining in second child is: 0 at level 3
First child process (PID: 8580) with parent process (PID: 8576) at level: 3
current remaining in first child is: 0 at level 3
Second child process (PID: 8582) with parent process (PID: 8576) at level: 3
current remaining in second child is: 0 at level 3

第一个电话就生了两个孩子 第二个电话产生了 4 个孩子 第三次调用得到 4,但应该是 3。

c++ unix fork
1个回答
0
投票

您希望每个进程最多

fork()
两次,因此您不应该需要任何循环、递归或类似的东西。

给定命令行参数

9
,以下程序将打印 10次
Terminating.
和9次
Waited for: <pid>
,这似乎是您的图片所指定的。

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

#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <sstream>

namespace {
struct Process {
  Process(pid_t pid) : pid{pid} { if (pid == -1) throw -1; }
  bool is_child() const { return pid == 0; }
  void disarm() { pid = 0; }
  ~Process() { if (pid)
    std::cout << (std::stringstream{}
              << "Waited for: " << waitpid(pid, nullptr, 0) << '\n').str(); }
 private:
  pid_t pid;
};

struct Blah { ~Blah() { std::cout << "Terminating.\n"; } };
}  // namespace

int main(int argc, const char *const argv[]) {
  Blah blah;
  if (argc != 2) return EXIT_FAILURE;
  size_t remaining;
  if (!(std::stringstream{argv[1]} >> remaining)) return EXIT_FAILURE;
fork_again:
  const size_t old_remaining{remaining};
  remaining = old_remaining / 2 + old_remaining % 2;
  if (!remaining) return EXIT_SUCCESS;
  Process firstFork{fork()};
  if (firstFork.is_child()) {
    if (--remaining) goto fork_again; else return EXIT_SUCCESS;
  }
  remaining = old_remaining - remaining;
  if (!remaining) return EXIT_SUCCESS;
  const Process secondFork{fork()};
  if (secondFork.is_child()) {
    firstFork.disarm();
    if (--remaining) goto fork_again;
  }
}

看待它的一种方式是,只需两个不受约束的

fork()
,它就相当于 Bash 中的这种令人敬畏的功能:

_()(_&_&);_ 

为了抑制进程数量的指数增长,当我们沿着

fork()
树向上移动时,我们限制进程可以
fork()
的次数,并且该数字呈指数下降。剩下的就是让所有细节(在某种程度上)正确。第一个子树被授予
remaining / 2 + remaining % 2
中的
fork()
,第二个子树获得其余的。这可以正确处理奇数和偶数情况。此外,除了原始(祖)父进程之外的所有进程也必须计算它们自己,这就是为什么它们总是以
--remaining
开始。

由于

goto
,在这段代码中使用 RAII 在可读性方面存在一些争议。我几乎确信有一种方法可以实现这一点,而无需向后跳转
goto
语句,但我也懒得弄清楚这一点。

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