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. JSON格式的服务接口

    电商接口 京东获取单个商品价格接口: http://p.3.cn/prices/mgets?skuIds=J_商品ID&type=1 用例 ps:商品ID这么获取:http://item.jd ...

  2. 大约laravel错误的解决方案

    2015-3-13 夜晚 9:13 执行laravel发生错误Indirect modification of overloaded element of BbsArticle has no effe ...

  3. python 教程 第六章、 模块

    第六章. 模块 1) 模块 sys模块 字节编译的.pyc文件,优化编译后生成pyo文件 2) from..import语句 import sys print 'The command line ar ...

  4. UVA - 825Walking on the Safe Side(dp)

    id=19217">称号: UVA - 825Walking on the Safe Side(dp) 题目大意:给出一个n * m的矩阵.起点是1 * 1,终点是n * m.这个矩阵 ...

  5. 利用属性中设置、查看DataContext Command等

    DataContext   1   2   3 示例   1   2 xaml代码自动生成   3

  6. TVideoCapture类的源码,继承TCustomPanel,用于视频捕获(用到了SendMessage和SetWindowPos等API)good

    unit VideoCapture; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, ...

  7. [原译]WPF绘制圆角多边形

    原文:[原译]WPF绘制圆角多边形 介绍 最近,我发现我需要个圆角多边形.而且是需要在运行时从用户界面来绘制.WPF有多边形.但是不支持圆角.我搜索了一下.也没找到可行的现成例子.于是就自己做吧.本文 ...

  8. [WPF]获取控件间的相对位置

    原文:[WPF]获取控件间的相对位置 [WPF]获取控件间的相对位置                             周银辉 我们知道WPF有着比较灵活的布局方式,关于某个控件的坐标,Canv ...

  9. windows下的getopt/getoptlong函数(拷贝GNU C的库函数)

    http://www.cnblogs.com/oloroso/p/4856104.html

  10. Qt打开外部程序和文件夹需要注意的细节(注意QProcess的空格问题,以及打开本地文件时,需要QUrl::fromLocalFile才可以)

    下午写程序中遇到几个小细节,需要在这里记录一下. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 QProcess *process = new QProcess(this ...