【转】FORK()函数的理解

fork()函数有关实验及解析 fork()是什么? fork()的原理其实非常简单:当你调用fork()时,会产生一个子进程,这个子进程会拥有父进程所有的东西(记住,是所有)更通俗一点来讲,在函数代码段中,调用fork后,调用一次,返回两次,如果返回0,则代表当前的进程是子进程,不是的话则是父进程。接下来我们看段代码深入理解一下: int main(int argc, char *argv[]) { pid_t pi... 阅读详情

对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。

  首先我们来看下fork函数的原型:

  #include <sys/types.h>

  #include <unistd.h>

  pid_t fork(void);

  返回值:

  负数:如果出错,则fork()返回-1,此时没有创建新的进程。最初的进程仍然运行。

  零:在子进程中,fork()返回0

  正数:在父进程中,fork()返回正的子进程的PID

  其次我们来看下如何利用fork创建子进程。

  创建子进程的样板代码如下所示:

  pid_t child;

  if((child = fork())<0)

  /*错误处理*/

  else if(child == 0)

  /*这是新进程*/

  else

  /*这是最初的父进程*/

  fock函数调用一次却返回两次;向父进程返回子进程的ID,向子进程中返回0,

  这是因为父进程可能存在很多过子进程,所以必须通过这个返回的子进程ID来跟踪子进程,

  而子进程只有一个父进程,他的ID可以通过getppid取得。

  下面我们来对比一下两个例子:

  第一个:

  #include <unistd.h>

  #include <stdio.h>

  int main()

  {

  pid_t pid;

  int count=0;

  pid = fork();

  printf( "This is first time, pid = %d/n", pid );

  printf( "This is second time, pid = %d/n", pid );

  count++;

  printf( "count = %d/n", count );

  if ( pid>0 )

  {

  printf( "This is the parent process,the child has the pid:%d/n", pid );

  }

  else if ( !pid )

  {

  printf( "This is the child process./n")

  }

  else

  {

  printf( "fork failed./n" );

  }

  printf( "This is third time, pid = %d/n", pid );

  printf( "This is fouth time, pid = %d/n", pid );

  return 0;

  }

  运行结果如下:

  问题:

  这个结果很奇怪了,为什么printf的语句执行两次,而那句“count++;”的语句却只执行了一次

  接着看:

  #include <unistd.h>

  #include <stdio.h>

  int main(void)

  {

  pid_t pid;

  int count=0;

  pid = fork();

  printf( "Now, the pid returned by calling fork() is %d/n", pid );

  if ( pid>0 )

  {

  printf( "This is the parent process,the child has the pid:%d/n", pid );

  printf( "In the parent process,count = %d/n", count );

  }

  else if ( !pid )

  {

  printf( "This is the child process./n");

  printf( "Do your own things here./n" );

  count ++;

  printf( "In the child process, count = %d/n", count );

  }

  else

  {

  printf( "fork failed./n" );

  }

  return 0;

  }

  运行结果如下:

  现在来解释上面提出的问题。

  看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if ( pid>0 )……。

  两个进程中,原先就存在的那个被称作“父进程”,新出现的那个被称作“子进程”。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

  1. 在父进程中,fork返回新创建子进程的进程ID;

  2.在子进程中,fork返回0;

  3.如果出现错误,fork返回一个负值;

  fork出错可能有两种原因:(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。(2)系统内存不足,这时errno的值被设置为ENOMEM。

  接下来我们来看看APUE2中对fork的说明:

  The new process created by fork is called the child process. This function is called once but returns twice. The only difference in the returns is that the return value in the child is 0, whereas the return value in the parent is the process ID of the new child. The reason the child's process ID is returned to the parent is that a process can have more than one child, and there is no function that allows a process to o^ain the process IDs of its children. The reason fork returns 0 to the child is that a process can have only a single parent, and the child can always call getppid to o^ain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so it's not possible for 0 to be the process ID of a child.)

  被fork创建的新进程叫做自进程。fork函数被调用一次,却两次返回。返回值唯一的区别是在子进程中返回0,而在父进程中返回子进程的pid。在父进程中要返回子进程的pid的原因是父进程可能有不止一个子进程,而一个进程又没有任何函数可以得到他的子进程的pid。

  Both the child and the parent continue executing with the instruction that follows the call to fork. The child is a copy of the parent. For example, the child gets a copy of the parent's data space, heap, and stack. Note that this is a copy for the child; the parent and the child do not share these portions of memory. The parent and the child share the text segment (Section 7.6).

  子进程和父进程都执行在fork函数调用之后的代码,子进程是父进程的一个拷贝。例如,父进程的数据空间、堆栈空间都会给子进程一个拷贝,而不是共享这些内存。

  Current implementations don't perform. a complete copy of the parent's data, stack, and heap, since a fork is often followed by an exec. Instead, a technique called copy-on-write (COW) is used. These regions are shared by the parent and the child and have their protection changed by the kernel to read-only. If either process tries to modify these regions, the kernel then makes a copy of that piece of memory only, typically a "page" in a virtual memory system. Section 9.2 of Bach [1986] and Sections 5.6 and 5.7 of McKusick et al. [1996] provide more detail on this feature.

  我们来给出详细的注释

  #include <unistd.h>

  #include <stdio.h>

  int main(void)

  {

  pid_t pid;

  int count=0;

  /*此处,执行fork调用,创建了一个新的进程, 这个进程共享父进程的数据和堆栈空间等,这之后的代码指令为子进程创建了一个拷贝。 fock 调用是一个复制进程,fock 不象线程需提供一个函数做为入口, fock调用后,新进程的入口就在 fock的下一条语句。*/

  pid = fork();

  /*此处的pid的值,可以说明fork调用后,目前执行的是父进程还是子进程*/

  printf( "Now, the pid returned by calling fork() is %d/n", pid );

  if ( pid>0 )

  {

  /*当fork在子进程中返回后,fork调用又向父进程中返回子进程的pid, 如是该段代码被执行,但是注意的事,count仍然为0, 因为父进程中的count始终没有被重新赋值,  这里就可以看出子进程的数据和堆栈空间和父进程是独立的,而不是共享数据*/

  printf( "This is the parent process,the child has the pid:%d/n", pid );

  printf( "In the parent process,count = %d/n", count );

  }

  else if ( !pid )

  { /*在子进程中对count进行自加1的操作,但是并没有影响到父进程中的count值,父进程中的count值仍然为0*/

  printf( "This is the child process./n");

  printf( "Do your own things here./n" );

  count++;

  printf( "In the child process, count = %d/n", count );

  }

  else

  {

  printf( "fork failed./n" );

  }

  return 0;

  }

  也就是说,在Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。"代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段。

  仔细分析后,我们就可以知道:

  一个程序一旦调用fork函数,系统就为一个新的进程准备了前述三个段,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。

  fork()不仅创建出与父进程代码相同的子进程,而且父进程在fork执行点的所有上下文场景也被自动复制到子进程中,包括:

  ——全局和局部变量

  ——打开的文件句柄

  ——共享内存、消息等同步对象

  而如果两个进程要共享什么数据的话,就要使用另一套函数(shmget,shmat,shmdt等)来操作。现在,已经是两个进程了,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零,这样,对于程序,只要判断fork函数的返回值,就知道自己是处于父进程还是子进程中。

C fork()&&fork()||fork() 一道关于fork创建进程个数的题目: #include int main() {   fork(); fork()&&fork()||fork(); fork(); return 0; } 问除了第一个父进程,这个程序到底创建了多少进程? 这道题主要考了两个知识点,一是逻辑运算符运行的特点;二是对fork理解。 如果有一个这样的表达式:cond1 && cond2 || 阅读详情

相关推荐

1、微软 Intune 全面指南:配置、管理与自动化

本文全面介绍了微软 Intune 的配置、管理和自动化操作,涵盖用户与设备管理、安全策略设置、跨平台应用部署、合规性监控及报告分析等内容。通过详细的操作步骤、自动化脚本示例和流程优化建议,帮助技术人员高效掌握 Intune 在混合办公环境中的实际应用,并展望其未来发展趋势。

ii567的博客 281

fork()使用详解

一、fork入门知识 进程的定义: 进程是一个执行中的程序的实例,是系统进行资源分配和调度的一个独立单位。 PCB是进程存在的唯一标识。PCB应常驻内存,不管在linux还是windows中都有专门区域存储每个进程的PCB。 进程的创建: 子进程可以继承父进程所拥有的所有资源,当子进程被撤销时,应将其从父进程那里获得的所有资源归还给父进程,在撤销父进时,也必须同时撤销其所有子进程。 进...

桐原因的博客 2278

【skill】漫剧 AI 视频创作的知识库 + API 调用手册

方案适用场景在对话中使用,自动触发注入到任何 LLM(Cursor/Windsurf/Claude API)Python 模块集成到自动化管线/批量生成GitHub 又限速了,不过前几轮搜到的已经够用了。根据搜索结果,结合已分析过的项目,给你整理完整对比 🐮。

突围 610

linuxfork() 函数详解

fork入门知识 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了...

weixin_33804990的博客 2873

FORK()函数理解

    作者:王姗姗,华清远见嵌入式学院讲师。广告插播信息维库最新热卖芯片: 74LS04 MC33341DR2 SN74ABT16541ADGGR TMP68301AF-12 CDC2510CPWR MC68HC912B32CFU8 EP1K10TC100-3N ADM211AR ST92F120V9Q7 HRF3205   对于刚刚接触Unix/Linux操作系统,在Linux

jphaoren的专栏 1427

Fork使用教程

4.1.首先先确定主分支和丛分支,以这个图为例再develop分支上,develop(A 1.4)节点就是主分支,Recent(B1.2节点)就是丛分支。A1.5是B1.2和A1.4合并到develop分支上形成的。

weixin_56761019的博客 5626

关于fork函数的使用

基本必备知识 fork函数的基本说明 介绍 fork函数用于创建一个新的进程,下面引用一段话介绍一下: 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后...

培纪的博客 1240

[]fork()函数理解

对于刚刚接触Unix/Linux操作系统,在Linux下 编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。   首先我们来看下fork函数的原型:   #i nclude    #i nclude   pid_t fork(void);   返回值:   负数:如果出错,则fork()返回-1,此时没有创建 新的进程。最初的进程仍然运行。   零:在子进

leafqing04的专栏 604

Linux系统——fork()函数详解(看这一篇就够了!!!)

fork()函数详解(包看包会!!!) 1.fork()简介 函数原型: pid_t fork(void);//pid_t为int类型,进行了重载 pid_t getpid();// 获取当前进程的 pid 值。 pid_t getppid(); //获取当前进程的父进程 pid 值。 用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化; 如图所示 :我们将A 进程, 也就是调用 for

cckluv的博客 8万+

fork()函数详解

目录 1.基本了解: 2.fork函数的了解: 3.僵死进程: 1.基本了解: 一个进程,包括代码、数据和分配给进程的资源。fork 函数会新生成一个进程,调用 fork 函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的 pid,在子进程中返回 0,失败返回-1。 为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值: 1)在父进程中,fork返回新创建子进程的进程...

weixin_57133901的博客 4万+

fork()函数

问题导入:大家应该都对进程有一个概念,我们从硬盘上找到我们写下的.c文件代码,在linux中我们通过输入驱动命令让预处理器、编译器、汇编器和连接器给我们最后生成一个可 执行的目标文件,然后再给一个执行命令,将这个可执行的文件加载进内存执行。就在可执行文件加载进内存的时候,生成一个新的进程,供cpu管理和控制它的执行。那这里就有一个疑问了, 这里cpu是自动为我们生成了一个进程,它是怎样

Betty2017的博客 1641

操作系统学习心得之——fork()函数

接下来大概 XXX 分钟里,我将根据老师给的三道例题,用我认为最通俗易懂的讲解带大家理解fork()函数fork()函数基础 首先是对这个函数的介绍,fork()函数很特别,似乎仅存在在Linux系统里。(我才疏学浅,可能还有其他系统里也可以使用但我不知道)它的作用是创建一个新的进程,同时在不同进程里又会有不同的值。在父进程里,fork()函数的值是子函数的pid,而在子函数里,fo...

weixin_44019423的博客 2363

os.fork()函数理解

os.fork()函数官方文档解释。 fork是分叉的意思。根据官方文档我的理解是从主进程执行到fork函数部分开始分叉执行。(fork函数创建了一个子进程与主进程一起在cpu内执行。) os.fork()函数代码。 import os if __name__ == '__main__': print("This is fork process") pid = os.fork() if pid == 0: print("This is child proces.

weixin_43751285的博客 1391

C fork()函数详解

一、fork入门知识      一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。     一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来

qq_29233719的博客 1531

详解fork()函数的两个返回值

-首先,在调用fork函数时,操作系统会从用户态切换到内核态来进行进程的创建,会调用fork函数中的_CREATE函数和_CLONE函数。 -在调用_CREATE函数时,子进程进行虚拟地址申请,在子进程的内核空间中进行不完全拷贝,因为PID作为每个进程的唯一标识符,就像每个人的身份证一样,是不可能完全一样的,所以这个地方时不完全拷贝,所以PID就需要自己生成。 ...

qq_55914897的博客 6850

fork()函数用法理解

 #include #include #include int main(){pid_t pid;static int n = 0;printf(”fork!/n”); /*printf(”fork!”)*/switch (pid = fork()){case -1:{/* 这里pid为-1,fork函数失败 *//* 一些可能的原因是 *//* 进程数或虚拟内存用尽 */perror(”Th

在路上…… 2580

深度理解fork()函数及进程控制

进程创建 理解fork()函数 再谈fork()函数,从前面我们知道fork函数是从已经存在的进程中创建一个新进程,新进程为子进程,而原进程为父进程。它的返回值有两个:子进程返回0,父进程返回子进程id,出错返回-1 进程调用fork,当控制移到内核中的fork代码后,内核做的事情: 分配新的内存块和内核数据结构给子进程 将父进程部分数据结构内容拷贝给子进程 添加子进程到系统进程列...

TANGY的博客 866

基于ESP32开发的天气时钟。.zip

【项目资源】:适用于从基础到高级的各种项目,特别是在性能要求较高的场景中,比如操作系统开发、嵌入式编程和底层系统编程。如果您是初学者,可以从简单的控制台程序开始练习;如果是进阶开发者,可以尝试涉及硬件或网络的项目。【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。# 注意 1. 本资源仅用于开源学习和技术交流。不可商用等,一切后果由使用者承担。 2. 部分字体以及插图等来自网络,若是侵权请联系删除。

下一篇: JTAG--What is JTAG?
Elvin
博客等级 码龄19年 14粉丝 0原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值