use*_*779 33 linux fork process
所以,我已经习惯了fork()
,我知道它做了什么.作为初学者,我非常害怕它(我仍然不完全理解它).fork()
你可以在网上找到的一般描述是,它复制当前进程并分配不同的PID,父PID和进程将有不同的地址空间.一切都很好,但是,鉴于这个功能描述,初学者会想知道"为什么这个功能如此重要......为什么我要复制我的过程?".所以我确实很奇怪,最终我发现你可以通过execve()
家庭来调用当前流程中的其他流程.
我仍然不明白为什么你必须这样做?最合乎逻辑的是拥有一个可以调用的函数
create_process("executable_path+name",params..., more params);
Run Code Online (Sandbox Code Playgroud)
这会生成一个新进程并在main()的开头运行它并返回新的PID.
困扰我的是fork/execve解决方案正在进行可能不需要的工作的感觉.如果我的进程使用大量内存怎么办?内核是否复制了我的页面表等.我确信它不会真正分配实际内存,除非我触及它.另外,如果我有线程会发生什么?在我看来,它太乱了.
几乎所有关于fork的描述,比如它只是复制进程并且新进程在fork()
调用之后开始运行.这确实发生了什么,但为什么会这样发生?为什么fork/execve是产生新进程的唯一方法,以及从当前创建新进程的最常用的unix方法是什么?有没有其他更有效的方法来产生进程?**这不需要复制更多的内存.
这个帖子谈到同样的问题,但我发现它不太令人满意:
谢谢.
nin*_*alj 20
这是由于历史原因.正如https://www.bell-labs.com/usr/dmr/www/hist.html所解释的那样,早期的Unix确实既没有fork()
也没有exec*()
,并且shell执行命令的方式如下:
exit()
,然后通过重新加载shell(覆盖命令的内存)并跳转到它,返回到步骤1.从那里,fork()
是一个简单的添加(27条装配线),重用其余的代码.
在Unix开发的那个阶段,执行命令变为:
fork()
子进程,并等待它(通过向它发送消息).exit()
,这现在更简单了.它只是清理了它的进程,并放弃了控制权.本来,fork()
没写拷贝就写了.由于这种方法很fork()
昂贵,并且fork()
经常被用来产生新的进程(因此经常会紧随其后exec*()
),因此fork()
出现了一个优化版本:vfork()
它共享了父级和子级之间的内存.在那些实现中vfork()
,父项将被暂停,直到孩子exec*()
'ed或_exit()
'ed,从而放弃父母的记忆.后来,fork()
经过优化,可以在写入时进行复制,只有在父母和孩子之间开始不同时才制作内存页面的副本.vfork()
后来看到MMU系统对端口产生了新的兴趣(例如:如果你有一个ADSL路由器,它可能在一个MMU MIPS CPU上运行Linux),它无法进行COW优化,而且无法fork()
有效地支持'ed进程.
其他效率低下的原因fork()
是它最初复制了父级的地址空间(和页表),这可能使得从大型程序运行的短程序相对较慢,或者可能使操作系统拒绝fork()
认为可能没有足够的内存用于它(要解决此问题,您可以增加交换空间,或更改操作系统的内存过载设置).作为一则轶事,Java 7用于vfork()/posix_spawn()
避免这些问题.
另一方面,fork()
使创建同一进程的多个实例非常有效:例如:Web服务器可能有几个相同的进程为不同的客户端提供服务.其他平台也支持线程,因为产生不同进程的成本比复制当前进程的成本要大得多,这可能比生成新线程的成本要大一些.这是不幸的,因为共享 - 所有线程都是错误的磁铁.
Bas*_*tch 10
请记住,这fork
是在Unix(或许之前)很早就在机器上发明的,这些机器现在看起来非常小(例如64K字节的内存).
它与通过最基本的可能行动提供基本机制而非政策的整体(原始)理念更加同步.
fork
只是创建一个新流程,最简单的思维方式就是克隆当前流程.所以fork
语义是非常自然的,它是最简单的机制.
其他系统调用(execve
)负责加载新的可执行文件等.
将它们分开(并且也提供pipe
和dup2
系统调用)给出了很大的灵活性.
并且在当前系统上,fork
非常有效地实现(通过写分页技术的懒惰副本).众所周知,该fork
机制使得Unix进程创建速度非常快(例如,比在Windows或VAX/VMS上更快,系统调用创建的进程更类似于您的建议).
还有vfork系统调用,我不打扰使用.
并且posix_spawn API比复杂fork
或execve
单独复杂得多,因此说明fork
更简单...
就分页/虚拟内存而言,有些技术中 fork() 并不总是复制进程的整个地址空间。存在写时复制,其中分叉进程获取与其父进程相同的地址空间,然后仅复制(由任一进程)更改的空间的一部分。