精华内容
下载资源
问答
  • fork

    2019-10-27 15:06:53
    fork函数 fork函数从已经存在的进程中创建一个新的进程,新进程为子进程,原进程为父进程。子进程返回0,父进程返回子进程的pid。

    fork函数

    fork函数从已经存在的进程中创建一个新的进程,新进程为子进程,原进程为父进程。子进程返回0,父进程返回子进程的pid。

     #include<stdio.h>
     #include<unistd.h>
     #include<sys/types.h>
     int main()
     {
          int ret = fork();
          if(ret == 0)
          {
              printf("I am child : %d, ret: %d\n", getpid(), ret);
          }
          else if(ret > 0)
          {
              printf("I am father : %d, ret: %d\n", getpid(), ret);
          }
          else
          {
              perror("fork");
              return 1;
          }
          return 0;
      }
    

    进程调用fork,当控制转移到内核中的fork代码后,内核:

    1. 分配新的内存块和内核数据结构给子进程
    2. 将父进程的部分数据结构内容拷贝至子进程
    3. 添加子进程到系统进程列表当中
    4. fork返回,开始调度器调度

    写时拷贝

    父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)。
    在这里插入图片描述
    写时拷贝是一种采取了惰性优化方法来避免复制时的系统开销,多个进程读取同一份数据,如果全部复制会造成浪费,所以每个进程只要保存一个指向这个资源的指针就可以了,如果一个进程要修改自己的那份资源,那么就会复制那份资源,并把复制的那份提供给进程。

    展开全文
  • Unix/Linux fork前传

    万次阅读 多人点赞 2019-09-09 08:15:00
    本文是《Linux fork那些隐藏的开销》的前传。fork的由来fork的思想在UNIX出现几年前就出现了,时间大概是1963年,这比UNIX在PDP-7上的第一个版本...
        

    本文是《Linux fork那些隐藏的开销》的前传。

    fork的由来

    fork的思想在UNIX出现几年前就出现了,时间大概是1963年,这比UNIX在PDP-7上的第一个版本早了6年。

    1963年,计算机科学家Melvin Conway(以Conway’s Law闻名于世)写下一篇论文,正式提出了fork思想,该论文链接:A Multiprocessor System Design:

    https://archive.org/details/AMultiprocessorSystemDesignConway1963/page/n7

    fork的思想最初是Conway作为一种 多处理器并行 的方案提出来的,这个想法非常有意思。简而言之,fork思想来源于流程图。

    我们看一个普通的流程图:640?wx_fmt=png

    你看,流程图的分枝处,fork-叉子,多么形象!

    一个流程图上的分支点分裂出来的分支显然是逻辑独立的,这便是可并行的前提,于是它们便可以表现为不同的 处理进程(process) 的形式,当时的表达还只是“process”这个术语,它还不是现代操作系统意义上的“进程”的概念。

    join同步点表现为多个并行处理的进程由于某种原因不得不同步的点,也就是多个并行流程汇合的点,直到现在,在多线程编程中,这个点依然叫join。比如Java Thread的join方法以及pthread库的pthread_join函数。

    广义来讲,join也表示诸如临界区等必须串行通过的点, 减少join点的数量将会提高并行的效率。

    我们来看看Conway论文中关于fork的原始图示:640?wx_fmt=png

    Conway在论文中的另一个创举是,他将处理进程(也就是后来操作系统中的process的概念)以及执行该进程的处理器(即CPU核)分离了开来,抽象出了schedule层。

    大意是说, “只要满足系统中的活动处理器数量是总处理器数量和并行处理进程的最小值即可。” 这意味着调度程序可以将多处理器系统的所有处理器和系统所有处理进程分别看作是统一的资源池和消费者,执行统一调度:640?wx_fmt=png在UNIX引入fork之后,这种多处理器并行的设计思想就深入到了UNIX的核心。这个思想最终也影响了UNIX以及后来的Linux,直到现在。

    关于这个设计思想为什么可以影响UNIX这么久,我想和Conway本人的“Conway’s law”不无关系,在这个law中,他提到:Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.

    好了,fork本身的由来我们已经了解,就像做菜一样,现在我们把它放在一边备用。

    花开两朵,各表一枝。接下来看UNIX fork的另一个脉络。

    早期UNIX的覆盖(overlaying)技术

    1969年最初的UNIX用一种在现在看来非常奇怪的方式运行。

    一般的资料都是从UNIX v6版本开始讲起,那个版本已经是比较 “现代” 的版本了,所以很少有人能看到最初的UNIX是什么样子的。即便是能查阅到的1970年的PDP-7上运行的UNIX源码,也是引入fork之后的版本,在那之前的最原始版本几乎找不到了(你可能会说,那时的UNIX不叫UNIX,but who cares…)。

    1969年的汤普森版UNIX超级简陋,这可以在Dennis M. Ritchie的一篇论文中见一斑:The Evolution of the Unix Time-sharing System:

    http://www.read.seas.harvard.edu/~kohler/class/aosref/ritchie84evolution.pdf

    最初的UNIX是一个分时系统,它只有两个shell进程,分别属于两个终端:640?wx_fmt=png

    分时系统最初并不是基于进程分时的,那时根本还没有完整的进程的概念,分时系统是针对终端分时的,而操作员坐在终端前,为了让每个操作员在操作过程中感觉上是在独占机器资源,每个终端享受一段时间的时间片,在该时间片内,该终端前的操作员完全享受机器,但是为了公平,超过了时间片,时间片就要给另一个终端。

    就是这样,最初的UNIX为了体现分时特性,实现了最少的两个终端。注意,最初的UNIX没有fork,没有exec,甚至没有多进程的概念,为了实现分时,系统中仅有两个朴素的shell进程。

    事实上,最初的UNIX用只有两个元素的表来容纳所有进程(显然,这看起来好笑…),当然,这里的 “表” 的概念也是抽象的朴素概念,因为当时的系统是用PDP-7的汇编写的,还没有后来C语言数据结构。

    我们现在考虑其中一个终端的shell进程如何工作。马上问题就来了, 这个shell进程如何执行别的命令程序??

    如果说系统中最多只能容纳两个进程,一个终端只有一个shell进程的话,当该终端的shell进程执行其它命令程序时,它自己怎么办?这个问题得思考一会儿…

    注意,不要用现代的眼光去评价1969年的初版UNIX,按照现代的眼光,执行一个程序必然要生成一个新的进程,显然这在初版UNIX中并不正确。

    答案是根本不用产生新的进程,直接将命令程序的代码载入内存并 覆盖 掉shell进程的代码即可!当命令执行完后,再用shell的代码覆盖掉命令程序的代码,针对单独的终端,系统其实一直在执行下面的覆盖循环(摘自论文的Process control 章节):640?wx_fmt=png

    然而,在fork被引入UNIX之前,事实就是这样。一个终端上一直都是那一个进程,一会儿它执行shell的代码,一会儿它执行具体命令程序的代码,以下是一个覆盖程序的结构(图片来自《FreeBSD操作系统设计与实现》一书):640?wx_fmt=png

    然而,当时毕竟还没有将这个逻辑封装成exec系统调用,这些都是每一个进程显式完成的:

    • 对于shell执行命令程序而言,shell自己执行disk IO来载入命令程序覆盖掉自身;

    • 对于命令程序执行结束时,exit调用内部执行disk IO载入shell程序。

    exec逻辑是shell程序的一部分,由于它会被所有的命令程序所使用,该逻辑也被封装到了exit调用中。

    fork引入UNIX前的表象

    好了,目前为止,我们看完了两条线索:

    1. 1963年Melvin Conway提出了fork思想,作为在多处理器中并行执行进程的一个手段。

    2. 1969年汤普森版UNIX仅有两个shell进程,使用覆盖(overlaying)技术执行命令。

    截止目前,我们看到的表象是:

    • 汤普森版UNIX没有fork,没有exec,没有wait,仅有的库函数般的exit也和现在的exit系统调用大相径庭,显然汤普森版UNIX并非一个多进程系统,而只是一个可以跑的简陋的两终端分时系统!

    UNIX fork的诞生

    fork是如何引入UNIX的呢?

    这还要从采用覆盖技术的汤普森版UNIX所固有的问题说起,还是看论文原文:640?wx_fmt=png

    若要解决这些问题,很简单的方案汤普森都想到了:

    • 保持shell进程的驻留而不是销毁。命令执行时,将其交换到磁盘便是了

    很显然,命令程序是不能覆盖掉shell进程了。解决方案是使用 “交换” 技术。

    交换技术和覆盖技术其实都是解决有限内存的多进程使用问题的,不同点在于方向不同:

    • 覆盖技术指的是用不同的进程磁盘映像覆盖当前的进程内存映像。

    • 交换技术指的是用将进程的内存映像交换到磁盘,载入一个别的进程磁盘映像。

    使用交换技术解决覆盖的问题,意味着要创建新的进程:

    • 在新的进程中执行命令程序。

    UNIX需要进行改动,两个配额的进程表显然不够用了。当然,解决方案也并不麻烦:640?wx_fmt=png

    要讲效率,创造不如抄袭,创建新进程的最直接的就是copy当前shell进程,在copy的新进程中执行覆盖,命令程序覆盖copy的新进程,而当前的终端shell进程则被交换到磁盘保得全身。

    覆盖和交换相结合了,UNIX离现代化更近了一步!

    确定了copy当前进程的方案后,进一步的问题是如何来copy进程。

    现在要说回fork了。

    Conway提出fork思想后,马上就有了fork的实现原型(正如Conway自己所说,他只是提出了一个可能造就存在的想法,并没有实现它),Project Genie算是实现fork比较完善的系统之一了。

    Project Genie系统的fork不仅仅是盲目地copy进程,它对fork的过程拥有精细的控制权,比如分配多大的内存空间,copy哪些必要的资源等等。显然,Project Genie的fork是冲着Conway的多处理器并行逻辑去的。

    还是那句话,创造不如抄袭,UNIX若想实现进程copy,有一个现成的模版就是Project Genie,但是Project Genie的fork对于UNIX太过复杂,太过精细化了,UNIX显然用不到这些精细的控制, UNIX仅仅是想让fork出来的新进程被覆盖,而不是让它去执行什么多处理器上的并行逻辑。

    换句话说,UNIX只是借用了fork的copy逻辑的实现,来完成一件别的事。

    于是,UNIX非常粗暴的实现了fork!即完全copy父进程,这就是直到现在我们依然在使用的fork系统调用:640?wx_fmt=png

    取了个巧,奇技淫巧:

    • fork本来就不是让你用来覆盖新进程的,不然为何多此一举。fork是让你来分解程序流程得以并行处理的。

    UNIX fork就此诞生!

    我们再次回顾一下UNIX fork诞生之前的景象:640?wx_fmt=png

    再来看看fork诞生之后的景象:640?wx_fmt=png640?wx_fmt=png

    于是UNIX正式迈开了现代化建设的步伐,一直走到了今天。

    UNIX fork-exec

    关于exec,故事没什么好讲的,它事实上就是关于上述覆盖逻辑的封装,此后程序员不必自己写覆盖逻辑了,直接调用exec系统调用即可。

    于是经典的UNIX fork-exec序列便形成了。

    UNIX fork/exec/exit/wait

    值得一提的是,fork被引入UNIX后,exit的语义发生了巨大的改变。

    在原始的1969年汤普森版UNIX中,由于每一个终端有且仅有一个进程,这意味着覆盖永远是在shell程序和某个命令程序之间进行的:

    • shell执行命令A:命令程序A覆盖内存中的shell代码。

    • 命令A执行结束:shell覆盖结束的命令A的内存代码。

    然而,在fork被引入后,虽然shell执行某个命令依然是特定的命令程序覆盖fork出来的shell子进程,但是当命令执行完毕后,exit逻辑却不能再让shell覆盖当前命令程序了,因为shell从来就没有结束过,它作为父进程只是被交换到了磁盘而已(后来内存到了,可以容纳多个进程时,连交换都不需要了)。

    那么exit将让谁来覆盖当前进程呢?

    答案是不用覆盖,按照exit的字面意思,它只要结束自己就可以了。

    本着 自己的资源自己管理的责任原则 exit只需要清理掉自己分配的资源即可。比如清理掉自己的内存空间以及一些其它的数据结构。

    对于子进程本身而言,由于它是父进程生成的,所以它便由父进程来管理释放。于是经典的UNIX进程管理四件套正式形成:640?wx_fmt=png                                                   (完)

    浙江温州皮鞋湿,下雨进水不会胖!

    查看我们精华技术文章请移步: Linux阅码场原创精华文章汇总

    更多精彩,尽在"Linux阅码场",扫描下方二维码关注

    640?wx_fmt=png

    感谢您的耐心阅读,请随手转发一下或者点个“在看”吧~

    展开全文
  • php中pcntl_fork详解

    万次阅读 2020-06-19 14:38:34
    ** pcntl_fork()函数是php-pcntl模块中用于创建进程的函数。(不支持windows) ...当:pcntl_fork()函数执行的时候,会创建一个子进程。子进程会复制当前进程,也就是父进程的所有:数据,代码,还有状态。

    pcntl_fork()函数是php-pcntl模块中用于创建进程的函数。(不支持windows)

    至于php_pcntl扩展如何安装开启这里就不介绍了,只分析pcntl_fork()这个函数本身。

    $one = 123;
    $one++;
    $two = time();
    $pid = [];
    $pid = pcntl_fork();
    $three = time();
    

    当:pcntl_fork()函数执行的时候,会创建一个子进程。子进程会复制当前进程,也就是父进程的所有:数据,代码,还有状态。

    1.当pcntl_fork()创建子进程成功后,在父进程内,返回子进程号,在子进程内返回0,失败则返回-1

    2.子进程会复制父进程的代码,数据。那么就说明:子,父进程拥有的代码和数据会一模一样。

    3.重点:子进程会复制父进程的状态,那么就有上面的示例代码:在第五行执行了pcntl_fork,那么创建出的子进程,代码也是从第五行开始执行的。又子进程复制了数据,代码。所以,在子进程内同理存在:$one,$two等变量

    for ($i = 0; $i < 3; $i++) {
        $pid = pcntl_fork();
    }
    sleep(30);
    

    那么:上面的for循环,实际会产生多少个子进程?答案是7个,在linux下,用ps命令将可以看到8个进程(1个父进程,7个子进程)
    原因:父进程在i=00i=0时,创建出一个子进程0,此时的子进程,还会继续执行循环。创建出属于自己的子进程。同理:i=1时也会这样……

    展开全文
  • Greasy Fork,这里是一个提供用户脚本的网站。 https://greasyfork.org/zh-CN Greasy Fork,这里是一个提供用户脚本的网站。

    油猴脚本 Greasy Fork,这里是一个提供用户脚本的网站。油猴脚本
    [https://greasyfork.org/zh-CN]
    点此处直达
    油猴脚本 Greasy Fork,这里是一个提供用户脚本的网站。油猴脚本

    展开全文
  • Fork/Join框架及模拟业务代码实现

    万次阅读 2018-06-27 11:53:58
    1.什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过Fork和Join这两个单词来...
  • Linux中fork()函数详解

    万次阅读 多人点赞 2018-08-12 04:42:38
    linux中fork()函数详解 一、fork入门知识 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程, 也就是两个进程可以做完全相同的事,但如果初始...
  • fork && fork || fork问题

    2017-08-10 10:05:11
    #include #include int main() { fork();/*****/ fork() && fork() || fork();/*****/ fork();/*****/ sleep(100); return 0; 问题是
  • linux下fork指令

    千次阅读 2018-10-20 18:42:22
    fork
  • fork() || fork()和fork() && fork()笔试题

    千次阅读 2017-02-12 23:17:11
    程序一:int main() { fork() || fork(); printf("+"); return 0; } 结果输出3个”+”,共创建3个进程。...在main这个主进程中,首先执行 fork() || fork(), 左边的fork()返回一个非零值,根据||的短路
  • Linux fork隐藏的开销-过时的fork(正传)

    千次阅读 多人点赞 2019-09-03 23:20:56
    本文来自《Linux fork那些隐藏的开销》 fork是一个拥有50年历史的陈年系统调用,它是一个传奇!时至今日,它依旧灿烂。 一个程序员可以永远不用read/write,也可以不懂mmap,但必须懂fork。这是一种格调! fork没有...
  • soft fork and hard fork

    2018-07-22 08:56:00
    &#13; https://bitcoin.stackexchange.com/questions/30817/what-is-a-soft-fork/ ...What is a Project Fork? A fork in software dev...
  • ![图片说明](https://img-ask.csdn.net/upload/201910/18/1571365804_10337.png) # 码云fork仓库时,没有显示我的fork位置,这该怎么解决???
  • fork() && fork() || fork()

    2019-07-23 14:27:23
    fork() && fork() || fork() http://blog.csdn.net/hs794502825/article/details/10242091 #include <unistd.h> #include <stdio.h> int main() { fork();// fork() && fork() || fork...
  • fork工具mac版本

    2018-05-29 09:43:34
    fork工具mac版本fork工具mac版本fork工具mac版本fork工具mac版本
  • fork process

    2019-08-10 16:12:51
    #include <stdlib.h> #include <unistd.h> #include <iostream> using namespace std; class fork_process { public: static inline fork_process &... static fork_process...
  • #include <unistd.h> #include <stdio.h> int main() { fork(); fork() &... fork() || fork(); fork(); printf("+ \n"); return 0; } 这段代码一共创建了20个进...
  • Fork仓库

    千次阅读 2018-08-30 14:42:12
    在版本控制术语中,如果你 “fork” 一个仓库,则是指复制它。特别是当你 fork 属于别人的仓库时,你将制作他们仓库的完全一样的副本,之后这个副本便变成你的。 “fork” 的概念也不同于”克隆”。在克隆仓库时,...
  • fork函数

    2019-01-06 19:12:20
    5.1 fork函数 fork函数是unix唯一的进程创建方法 #include "unistd.h" pid_t fork(void); /*在子进程中为0,在父进程中为子进程的ID,若出错则为-1*/ fork在子进程返回0而不是父进程的进程ID的原因是:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 83,154
精华内容 33,261
关键字:

fork