Perl和操作系统交互(二):fork
fork + exec
fork是低层次的系统调用,通过复制父进程来创建子进程。
fork的行为
fork用来拷贝当前进程,生成一个基本完全一样的子进程。
my $pid=fork();
如果fork成功:
- 则表示成功创建子进程,这时会有两条执行路线:继续执行父进程、执行子进程
- fork成功时,会返回两个值:对父进程返回子进程的pid,对子进程返回0
如果fork失败,将对父进程返回undef,并设置错误信息。fork失败的可能原因有:
- 内核内存不够,无法申请内存来fork
- 达到了允许的最大进程数量(进程数上限)
- 达到了rlimit限制的某种资源上限
例如:
#!/usr/bin/perl
#
use 5.010;
my $pid=fork();
say $pid,"======";
执行该程序,将返回两行数据:
62620======
0======
其中第一行输出是父进程输出的,第二行是子进程输出的。
虽然这里父进程先输出,但fork成功之后,父、子进程并没有执行的先后顺序,也可能cpu会先调度到上子进程去执行。

注意上图中子进程部分只画了"say"那行语句,但实际上子进程是完全复制父进程的,子进程也可以有say前面的那段语句(比如那个fork语句),但由于父进程的状态已经执行完了fork,所以子进程也是从fork语句之后开始执行的,fork语句之前的语句对于子进程来说是透明的。而且按照写时复制的技术,子进程用不到它所以不会复制fork前面的代码(注:也就是说子进程和父进程是共享代码的)。
更复杂一点的例子:
#!/usr/bin/perl
#
use 5.010;
print "id1: ",$pid,"\n";
my $pid=fork;
print "id2: ",$pid,"\n";
if(!$pid){ # ==0 exec
say "child process: ",$pid;
}
waitpid($pid,0);
say "parent process: ",$pid;
首先perl进程输出id1。然后fork一个子进程,这时有两条执行路线。假如fork后先执行父进程,则:
- 此父进程将输出id2
- 然后判断pid的值,因为fork返回给父进程的的pid变量值为子进程的进程号,所以不会等于0,于是if判断不通过
- 继续执行waitpid(),它将等待子进程执行结束,以下是子进程的执行过程:
- 子进程首先输出id2
- 然后判断
$pid,由于fork返回给子进程的pid变量值为0,所以if判断通过,于是子进程输出"child process" - 继续执行waitpid(),由于
$pid=0,waitpid()的等待pid为0时,表示等待以自己为leader进程的进程组中的其它进程,由于没有进程组,所以waitpid失败 - 继续执行,输出"parent process"
- 子进程执行完毕
- 父进程的waitpid()等待子进程执行完毕,继续向下执行
- 父进程输出"parent process"
假如fork之后,先执行子进程,且还先把子进程执行完了,cpu才调度到父进程,则也没有影响,子进程执行完毕后,迟早会调度到父进程,而父进程的waitpid($pid)已经没有子进程了,于是waitpid()失败(返回-1),继续向下执行。

显然,上面fork的代码有一些问题。由于fork创建子进程之后。父、子进程都继续执行,且执行的先后顺序不定。所以:
- 在fork之后,应该紧接着判断是否是子进程,避免有些在操作父子中都执行
- 在父进程中等待子进程
- 在子进程中加入执行完后就退出子进程的动作,免得执行本该父进程执行的动作
大概代码如下:
my $pid=fork;
unless($pid){ # 判断子进程的语句紧跟着fork
CODE1;
exit; # 要让子进程退出
}
waitpid($pid,0); # 要等待子进程
CODE2;
fork和exec结合
一般fork和exec会一起用,fork用来创建新的子进程,exec启动一个程序替代当前子进程并在子进程结束时退出子进程。
例如system "date"命令,替换为低层次的fork+exec+waitpid。
defined(my $pid=fork) or die "Cannot fork: $!";
unless($pid){
# 进入到这里执行的,表示进入子进程
exec 'date'; # exec正确执行时,执行完后将结束子进程
die "cannot exec date: $!"; # exec启动失败时,将执行die来结束子进程
}
# 这里的表示是父进程
waitpid($pid,0);
system、exec、fork等的区别
第一个人解释:
- exec replaces the current process with another one.
- system runs another program, wait for its completion.
- fork copies the current process; both the original and the copy continue from the same point.
- pipe sets up a pipe between two handles.
- syscall makes a low-level system call.
- eval executes (the string form will first compile) a piece of Perl code.
第二个人解释:
- exec is used to execute the given process by replacing the current process. If the given process get executed successfully then exec will not return the value. exec returns the value in case of failure only.
- System is also doing the same thing as exec but system returns value in both success and failure cases. And parent process waits for the child process to complete. System() runs the command through a shell,while exec() runs the command directly.
- fork is used to create a new process(child process). And it is returning the PID of child to parent and zero to child if the fork is successful. The difference between the fork and exec is exec replaces the current process but fork doesn't.
- pipe is used for communicating between two processes. We can use both named and nameless pipes. It returns open a pair of pipes. In one end we can write. And in another end we can read the content.
- syscall is used to call the system call which is specified as a first argument. Remaining elements are the arguments to the system call.
Perl和操作系统交互(二):fork的更多相关文章
- Perl和操作系统交互(一):system、exec和反引号
调用操作系统命令:system函数 system函数可以直接让perl调用操作系统中的命令并执行. system入门示例 例如: #!/usr/bin/perl system 'date +" ...
- VMware workstation批量创建虚拟机和自动化安装操作系统(二)
一. 简述 在上一篇<VMware workstation批量创建虚拟机和自动化安装操作系统(一)>中,主要介绍了VMware workstation自定义创建虚拟机的过程,和一些其他的有 ...
- Java和操作系统交互细节
结合 CPU 理解一行 Java 代码是怎么执行的 根据冯·诺依曼思想,计算机采用二进制作为数制基础,必须包含:运算器.控制器.存储设备,以及输入输出设备,如下图所示. enter image des ...
- Java和操作系统交互(Java 代码是怎么执行)(转)
结合 CPU 理解一行 Java 代码是怎么执行的 根据冯·诺依曼思想,计算机采用二进制作为数制基础,必须包含:运算器.控制器.存储设备,以及输入输出设备,如下图所示. 我们先来分析 CPU 的工作原 ...
- Java 和操作系统交互,你猜会发生什么?
作者:lonelysnow https://www.jianshu.com/p/7f6832d61880 结合 CPU 理解一行 Java 代码是怎么执行的 根据冯·诺依曼思想,计算机采用二进制作为数 ...
- 细说Oracle数据库与操作系统存储管理二三事
在上大学的时候,学习操作系统感觉特别枯燥,都是些条条框框的知识点,感觉和实际应用的关联不大.发现越是工作以后,在工作中越想深入了解,发现操作系统知识越发重要.在实践中结合理论还是不错的一种学习方法.自 ...
- 【操作系统】二、JVM线程与Linux内核线程的映射
Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...
- OS模块(与操作系统交互)
os 模块提供了很多允许你的程序与操作系统直接交互的功能 得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd() 返回指定目录下的所有文件和目录名:os.listdir() ...
- iOS下JS与原生的交互二
本篇主要讲的是UIWebView和JS的交互,UIWebView和JS交互的详解https://www.cnblogs.com/llhlj/p/6429431.html 一. WKWebView调用J ...
随机推荐
- <c:forEach>循环列表,获取勾选的checkbox中某个<td>的值
<table> <!--列表表头 开始 --> <tr> <th><input type="checkbox" name=&q ...
- oracle 恢复table删除数据 恢复package(使用闪回)
好久没写东西了,今天写一篇凑个数吧,来公司一年多了,感觉自己到了一个小瓶颈期了. 以前每天很多新东西,都是忙着学,感觉没时间写博客总结一下,大部分都是写笔记,现在又是没东西可以写,每天干着95%都是重 ...
- 没有job offer,拿加拿大工签PGWP回国如何续签加拿大小签?
很多同学因为在加拿大毕业后申请了三年的工作签证PGWP之后匆匆回国,没有来得及续签小签,但是回国一段时间之后又想要回加拿大,想要用自己的三年工签来续自己的小签.拿了加拿大PGWP没有job offe ...
- js的window.open()改写
说明:window.open(url,"_blank")方法替换如下: function openUrl(url) { try { if (/MSIE\s*(\d+\.\d+);/ ...
- sqoop错误集锦2
1.使用sqoop技术将mysql的数据导入到Hive出现的错误如下所示: 第一次使用命令如下所示: 1 [hadoop@slaver1 sqoop-1.4.5-cdh5.3.6]$ bin/sqoo ...
- Encrypt2
begin#33AB6770A8A98127BD0B5A6DAEC68E5E9385C02D24C850B12987FE36CF1A62738174C6FE5336E3B50048E836238582 ...
- Struts2新漏洞S2-046在线实验环境全球首发
Strust2 又出现漏洞啦?搞事情啊? 据说S2-046漏洞和S2-045漏洞非常相似,都是由报错信息带入了buildErrorMessage方法造成的, 只是这次存在两个触发点哦!危害嘛,你说嘞? ...
- Javascript高级编程学习笔记(24)—— 函数表达式(2)闭包
昨天的文章中主要记录了,函数表达式与函数声明的区别 以及在JS中如何安全地使用递归 那么既然要深入地理解JS中的函数,闭包就是一个绕不开的概念 闭包 JS高编一书中对闭包的概念定义如下: 闭包是指有权 ...
- Win10下python不同版本同时安装并解决pip共存问题
特别说明,本文是在Windows64位系统下进行的,32位系统请下载相应版本的安装包,安装方法类似. 使用python开发,环境有Python2和 python3 两种,有时候需要两种环境切换使用,下 ...
- pycharm激活方式
进入C:\Windows\System32\drivers\etc替换host文件,或者在host文件后加入0.0.0.0 account.jetbrains.com然后断网,断网,断网!最后输入K7 ...