有人可以解释 fork() 吗?

如何解决有人可以解释 fork() 吗?

有人能解释一下 fork() 并举例说明它的用法吗?

我从一些在线资源中了解到的是:

  1. fork() 创建一个子进程,其运行方式与父进程相同。
  2. 将创建 2^n 个进程,n = fork() 的数量。
  3. 子进程的 ID 将始终为 0,而父进程的 ID 将是其他内容 - 正整数 != 0。

我还有一个问题,首先请看我下面的代码:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
    int id = fork();
    int i = 45;
    fork();
    fork();
    if(id == 0) {
        printf("\nChild Process id = %d",id);
        printf("\ni = %d ; i = %d",i++,i);  
    }
    else {
        printf("\nParent Process id = %d",i,i+2);
    }
    return 0;
}   
/*
O/P:
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048                                                                                                                                                        
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
*/

为什么最后一个子进程不显示第二个 printf() 即,

printf("\ni = %d ; i = %d",i);

你能解释一下为什么第二个 printf() 没有被执行而第一个 printf() 被执行了 8 次 - 子进程。

解决方法

fork 的正确用法意味着立即测试当前进程是子进程(fork 返回 0)还是父进程(fork 返回子进程的 pid),并相应地采取行动。在您的情况下,父母和孩子都启动了一对或虚假的进程,它们将无法知道它们是什么,因为返回的值被忽略。其中一些会认为它们是父进程。

通常子进程会执行一个新的可执行文件,如果需要做一些严肃的事情。

,

fork() 创建与父进程运行相同的子进程。

没错。 fork() 创建一个子进程,它是它的父进程的副本。


将创建 2^n 个进程,n = fork() 的数量。

取决于代码!

int i = 0;
while (i < n)
{
    fork();
    i++;
}

这里,假设没有 fork() 失败,那么是的,会有 2^n 个进程。


子进程的 ID 将始终为 0,而父进程的 ID 将是其他东西 - 正整数 != 0。

子进程的fork() 返回值为0!不是id,而是返回值! 父进程fork()的返回值是子进程的实际pid


现在到你的代码

1. int main() {
2.    int id = fork(); 
3.    int i = 45;
4.    fork();
5.    fork();
6.    if(id == 0) {
7.        printf("\nChild Process id = %d",id);
8.        printf("\ni = %d ; i = %d",i++,i);  
9.    }
10.   else {
11.       printf("\nParent Process id = %d",id);
12.       printf("\ni = %d ; i = %d",i,i+2);
13.   }
14.   return 0;
15. } 

在第 4 行,有 2 个进程

parent         |     child_1
    id > 0     |     id == 0
    i == 45    |     i == 45     

现在调用一个fork

    parent     |     child_1    |    child_OF_1   |   child_2
    id > 0     |     id == 0    |    id == 0      |   id > 0
    i == 45    |     i == 45    |    i == 45      |   i == 45

child_1child_OF_1 将有 id == 0 并输入 if 语句,而 child_2parent 将转到 else 语句并打印 47

我忽略了第 3 个 fork(),那时你有 8 个进程,其中 4 个将进入 if 语句,而其他将进入 else 块。这就是为什么 你看

i = 45 ; i = 47

4 次!

,

您期望的所有输出都在那里,只是您在后台将其写出而无需终止换行。这意味着某些输出可能会被 shell 提示过早出现并出现在程序输出的中间而被掩盖或覆盖。

要确切了解这是如何实现的,以下是您程序中某些进程的 strace 输出:

3215092 write(1,"\n",1)               = 1
3215092 write(1,"Child Process id = 0\n",21) = 21
3215092 write(1,"i = 45 ; i = 46",15) = 15
3215094 write(1,1)               = 1
3215094 write(1,21) = 21
3215094 write(1,15) = 15

这里是 Zsh 如何绘制它的提示。首先是缺少换行指示符,然后是提示本身。特别注意,提示以 \r 开头,回车:

3215036 write(10,"\33[1m\33[3m%\33[23m\33[1m\33[0m          "...,306) = 306
3215036 write(10,"\r\33[0m\33[23m\33[24m\33[Jmyhostname.i"...,34) = 34

由于您在后台对写入终端的进程进行分叉,因此所有分叉的进程都在与 Zsh 竞争以写入其输出。

这是一种可能的、有效的排序,这可能导致:

1. 3215036 write(10,306) = 306
2. 3215092 write(1,1)               = 1
3. 3215092 write(1,21) = 21
4. 3215092 write(1,15) = 15
5. 3215094 write(1,1)               = 1
6. 3215094 write(1,21) = 21
7. 3215094 write(1,15) = 15
8. 3215036 write(10,34) = 34

第 1-7 步发生得相当顺利,结果是这样的屏幕(光标标有 |):

[...]
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46|

由于没有终止换行符,光标在最后一个字符串之后而不是在最后一个字符串之下。

现在,正如你在写 8 中看到的,Zsh 以一个前导回车开始它的默认提示。这意味着将转到行首:

[...]
i = 45 ; i = 46
Child Process id = 0
|i = 45 ; i = 46

然后继续用提示覆盖该行:

[...]
i = 45 ; i = 46
Child Process id = 0
myhostname.internal% 

实际上,即使输出的最后一行被写入屏幕,Zsh 提示通过使用回车符覆盖它来有效地擦除它。

您可以使用重定向来输出到文件,以便更清楚地看到您的程序产生的输出:

./foo > myfile

在编辑器中打开文件显示您的预期结果:

Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46

您可以类似地添加自己的终止换行符和延迟以在终端中显示输出:

./foo; sleep 5; echo

这给出了与上面相同的结果。

正确的程序会输出换行符after 而不是before 行,并且会为每个子进程wait()。 (请注意,如果您只修复其中一个,而保留另一个,则它将不起作用)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 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-