1. 关于fork

fork()函数:

   用于创建一个进程,所创建的进程复制父进程的代码段/数据段/BSS段/堆/栈等所有用户空间信息;在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化;

#include <iostream>
#include <unistd.h>
using namespace std;
int val = 10;
int main(int argc, char *argv[])
{
pid_t pid;
int lval = 20;

pid = fork();

if(pid == 0){
val += 2;
lval += 5;
}else{
val -= 2;
lval += 5;
}

if(pid == 0){
cout << "val:" << val << ", lval = " << lval << endl;
}else{
cout << "val:" << val << ", lval = " << lval << endl;
}
return 0;
}

对于父进程而言,fork()函数返回子进程的ID(子进程的PID);而对于子进程而言,fork函数返回0。

僵尸进程

  父进程创建子进程后,子进程运行到终止时刻(例如,调用exit()函数,或者运行到main中的return语句时,都会将返回的值传递给 操作系统),此时如果父进程还在运行,子进程并不会立即被销毁,直到这些值传到了产生该子进程的父进程。也就是说,如果父进程没有主动要求获得子进程的结束状态值,操作系统就会一直保存该进程的相关信息,并让子进程长时间处于僵尸状态,例如下面程序:

int main(){
pid_t pid = fork();
if(pid == 0){
cout << "I am a Child Process." <<endl;
}else{
cout << "I am a Father Process and Child Process is " << pid << endl;
sleep(30); //让父进程休眠30秒,此时便于观察子进程的状态
}
if(pid == 0){
cout << " Child Process exits " << endl;
}else{
cout << "Father Process exits " << endl;
}
return 0;
}

此时,运行该程序,查看后台进程可知(test16是该测试程序的名称,defunct表示僵尸进程):

gqx@gqx-Lenovo-Product:~$ ps -au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 0.6 0.9 tty7 Ssl+ 4月09 : /usr/lib/xorg/
root 0.0 0.0 tty1 Ss+ 4月09 : /sbin/agetty -
...
gqx 0.0 0.0 pts/ Z+ : : [tes16] <defunct>
gqx 0.0 0.0 pts/ R+ : : ps -au

僵尸进程的消除

方法一:调用wait()函数:

/* Wait for a child to die.  When one does, put its status in *STAT_LOC
and return its process ID. For errors, return (pid_t) -1.

This function is a cancellation point and therefore not marked with
__THROW. */
extern __pid_t wait (__WAIT_STATUS __stat_loc);

成功返回终止的进程ID,失败返回-1;子进程的最终返回值将指向该函数参数所指向的内存空间,但函数所指向的内存单元总还含有其他的信息,需要使用宏进行分离。

# define WIFEXITED(status)  __WIFEXITED (__WAIT_INT (status))  //子进程正常终止返回"true"
# define WEXITSTATUS(status) __WEXITSTATUS (__WAIT_INT (status)) //返回子进程的返回值

要注意的是:如果没有已终止的子进程,那么程序将被阻塞,直到有子进程终止。

方法二:调用waitpid()函数

/* Wait for a child matching PID to die.
If PID is greater than 0, match any process whose process ID is PID.
If PID is (pid_t) -1, match any process.
If PID is (pid_t) 0, match any process with the
same process group as the current process.
If PID is less than -1, match any process whose
process group is the absolute value of PID.
If the WNOHANG bit is set in OPTIONS, and that child
is not already dead, return (pid_t) 0. If successful,
return PID and store the dead child's status in STAT_LOC.
Return (pid_t) -1 for errors. If the WUNTRACED bit is
set in OPTIONS, return status for stopped children; otherwise don't.

This function is a cancellation point and therefore not marked with
__THROW. */
extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);

第一个参数:如果__pid的值是-1,则与wait()函数相同,可以等待任意的子程序终止;如果是0,则等待进程组识别码与目前进程相同的任何子进程;如果pid>0,则等待任何子进程识别码为 pid 的子进程。

第二个参数:与前一个函数wait()的参数意义相同。

第三个参数:常用WNOHANG——若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。

示例程序如下:

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
using namespace std;

void read_childproc(int sig){
int status;
pid_t id = waitpid(-1, &status, WNOHANG);
if(WIFEXITED(status)){
printf("Remove proc id: %d \n", id);
printf("Child send: %d \n", WEXITSTATUS(status));
}
}

int main(){
pid_t pid;
struct sigaction act;
act.sa_handler = read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, 0);

pid = fork();

if(pid == 0){
puts("Hi, I am a child process!");
sleep(6);
return 12;
}else{
printf("Child proc id: %d \n", pid);
pid = fork();
if(pid == 0){
puts("Hi, I am a child process!");
sleep(13);
exit(24);
}else{
int i;
printf("Child proc id: %d \n", pid);
for(i = 0; i < 4; i++){
puts("wait...");
sleep(5);
}
}
}
return 0;
}

  

fork和僵尸进程的更多相关文章

  1. fork()和僵尸进程

    2018-01-03@望京 关于fork()函数,Unix/Linux提供的fork()系统调用,fork()一次返回两次, 操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在 ...

  2. 为什么fork()2次会避免产生僵尸进程

    什么是僵尸进程:用fork()创建子进程后,子进程已终止但父进程没有对它进行善后处理,那么子进程的进程描述符就一直保存在内存中,子进程就是僵尸进程. 怎么产生僵尸进程: 1.父进程没有SIGCHLD信 ...

  3. 2次使用fork避免产生僵尸进程和不去处理SIGCHLD信号

    1.如下代码所示 #include <unistd.h> #include <sys/types.h> #include <unistd.h> int main(i ...

  4. 【转】Linux杀死fork产生的子进程的僵尸进程defunct

    僵尸进程 就是 已经结束,但是还没有清理出去的.用kill -9 $PID 也无法杀死. 所以程序中应该避免出现僵尸进程. 用fork之后,父进程如果没有wait /waitpid 等待子进程的话,子 ...

  5. 为何要fork()两次来避免产生僵尸进程??

    最近安装书上说的,开始搞多进程了..看到了一个好帖子,学习学习 http://blog.sina.com.cn/s/blog_9f1496990100y420.html 首先我们要明白,为什么要避免僵 ...

  6. 为何要fork()两次来避免产生僵尸进程?

    为何要fork()两次来避免产生僵尸进程?   当我们只fork()一次后,存在父进程和子进程.这时有两种方法来避免产生僵尸进程: 父进程调用waitpid()等函数来接收子进程退出状态. 父进程先结 ...

  7. 1.1 Linux中的进程 --fork、孤儿进程、僵尸进程、文件共享分析

    操作系统经典的三态如下: 1.就绪态 2.等待(阻塞) 3.运行态 其转换状态如下图所示: 操作系统内核中会维护多个队列,将不同状态的进程加入到不同的队列中,其中撤销是进程运行结束后,由内核收回. 以 ...

  8. linux系统编程之进程(三):进程复制fork,孤儿进程,僵尸进程

    本节目标: 复制进程映像 fork系统调用 孤儿进程.僵尸进程 写时复制 一,进程复制(或产生)      使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文.进程堆栈. ...

  9. UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

    本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID   1 进程标识符(Process Identifie ...

随机推荐

  1. 计算机的组成 —— 磁盘阵列(RAID)

    磁盘阵列(Redundant Arrays of Independent Disks,RAID),有"独立磁盘构成的具有冗余能力的阵列"之意.(另外一种常见阵列,FPGA:Fiel ...

  2. WPF 使用 SharpDX

    原文:WPF 使用 SharpDX 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问 ...

  3. OpenCV绘制朱利亚(Julia)集合图形

    朱利亚集合是一个在复平面上形成分形的点的集合.以法国数学家加斯顿·朱利亚(Gaston Julia)的名字命名. 朱利亚集合可以由下式进行反复迭代得到: 对于固定的复数c,取某一z值(如z = z0) ...

  4. 广义逆高斯分布(Generalized Inverse Gaussian Distribution)及修正贝塞尔函数

    1. PDF generalized inverse Gaussian distribution (GIG) 是一个三参数的连续型概率分布: f(x)=(a/b)p/22Kp(ab−−√)xp−1e− ...

  5. HDU-4432-Sum of divisors ( 2012 Asia Tianjin Regional Contest )

    Sum of divisors Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. sklearn 文本处理

    from sklearn.feature_extraction.text import ** 1. 向量的统计.tf-idf 的计算 考虑如下预料,三行 ⇒ 三个文档,不重复的单词共有 8 个, co ...

  7. CCD 与 CMOS

    窗帘快门与全局快门: 窗帘快门,每次只允许一条缝的光线摄入,因此会呈现自上而下的扫描式拍摄,也就意味着画面上的不同高度,其实拍摄的时间是不同的,也就进一步造成了在高速移动的火车上,如果拍摄窗外的景物, ...

  8. 【甘道夫】基于Mahout0.9+CDH5.2执行分布式ItemCF推荐算法

    环境: hadoop-2.5.0-cdh5.2.0 mahout-0.9-cdh5.2.0 引言 尽管Mahout已经宣布不再继续基于Mapreduce开发,迁移到Spark.可是实际面临的情况是公司 ...

  9. 淘宝平台进行数据的实时传输: TimeTunnel介绍

    在班级工作中遇到似业务场景中的实时流传输数据的访问,所以,淘宝实时数据仓库这个人做了一些研究和了解. 本文介绍的业务场景和淘宝的设计TimeTunnel工具,从淘宝数据仓库团队沟通过程中的图像文字si ...

  10. css 浏览器兼容性问题解决

    一个.!important (功能有限)   随着IE7正确!important支持, !important 方法现在只IE6兼容.(注意措辞.我记得这句话需要推进的位置.)   : #example ...