提问人:djflvv233 提问时间:11/16/2023 最后编辑:Ulrich Eckhardtdjflvv233 更新时间:11/16/2023 访问量:82
C++ 二进制分叉 UNIX 中的某个数字
C++ binary fork certain number in UNIX
问:
我正在学习 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
第一个电话就打了 2 个孩子 第二个电话使 4 个孩子 第三个调用是 4,但应该是 3。
答:
1赞
Andrej Podzimek
11/16/2023
#1
你希望每个进程最多两次,所以你不需要任何循环、递归或类似的东西。fork()
给定一个命令行参数,以下程序将打印 10 次和 9 次,这似乎是您的绘图指定的。9
Terminating.
Waited for: <pid>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <sstream>
namespace {
struct Process {
Process() : pid{fork()} { 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;
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;
if (secondFork.is_child()) {
firstFork.disarm();
if (--remaining) goto fork_again;
}
}
只有两个不受约束的 s,就相当于这个 Bash 的真棒:fork()
_()(_&_&);_
为了驯服进程数的指数增长,我们限制了进程在向上移动时可以进行的次数,如果我们想要一个恒定的总数,这个数字需要呈指数减少。fork()
fork()
fork()
剩下的就是把细节(在某种程度上)弄对了。第一个子树被授予 s,第二个子树获得其余的子树。这样可以正确处理奇数和偶数情况。此外,除原始(祖)父项以外的所有进程也必须计算自身,这就是为什么它们总是以 . 开头的原因remaining / 2 + remaining % 2
fork()
--remaining
由于 goto
,在可读性方面,在此代码中使用 RAII 是有争议的。我几乎可以肯定有一种方法可以在没有向后跳转语句的情况下实现它,但我也懒得弄清楚这一点。goto
评论
0赞
djflvv233
11/17/2023
谢谢你的解释!我成功地实施了这个程序。现在我了解了创建子进程的流程
评论
<iostream.h>
0..9