Linux进程理解与实践(二)僵尸&孤儿进程 和文件共享
孤儿进程与僵尸进程
孤儿进程:
如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <unistd.h>
- int main()
- {
- pid_t pid;
- //创建一个进程
- pid = fork();
- //创建失败
- if (pid < 0)
- {
- perror("fork error:");
- exit(1);
- }
- //子进程
- if (pid == 0)
- {
- printf("I am the child process.\n");
- //输出进程ID和父进程ID
- printf("pid: %d\tppid:%d\n",getpid(),getppid());
- printf("I will sleep five seconds.\n");
- //睡眠5s,保证父进程先退出
- sleep(5);
- printf("pid: %d\tppid:%d\n",getpid(),getppid());
- printf("child process is exited.\n");
- }
- //父进程
- else
- {
- printf("I am father process.\n");
- //父进程睡眠1s,保证子进程输出进程id
- sleep(1);
- printf("father process is exited.\n");
- }
- return 0;
- }
僵尸进程:
如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵尸进程。
- #include <stdio.h>
- #include <unistd.h>
- #include <errno.h>
- #include <stdlib.h>
- int main()
- {
- pid_t pid;
- pid = fork();
- if (pid < 0)
- {
- perror("fork error:");
- exit(1);
- }
- else if (pid == 0)
- {
- printf("I am child process.I am exiting.\n");
- exit(0);
- }
- printf("I am father process.I will sleep two seconds\n");
- //等待子进程先退出
- sleep(2);
- //输出进程信息
- system("ps -o pid,ppid,state,tty,command");
- printf("father process is exiting.\n");
- return 0;
- }
<defunct>僵尸进程
孤儿进程由init处理,并不会有什么危害。但是僵尸进程的大量存在会占用PID等资源,可能会导致系统无法产生新的进程。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个
子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理
避免僵尸进程
通过信号机制
子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:
- //示例: 避免僵尸进程
- int main(int argc, char *argv[])
- {
- signal(SIGCHLD, SIG_IGN);
- pid_t pid = fork();
- if (pid < 0)
- err_exit("fork error");
- else if (pid == 0)
- exit(0);
- else
- {
- sleep(50);
- }
- exit(0);
- }
文件共享
父进程的所有文件描述符都被复制到子进程中, 就好像调用了dup函数, 父进程和子进程每个相同的打开文件描述符共享一个文件表项(因此, 父子进程共享同一个文件偏移量);
- //根据上图: 理解下面这段程序和下图的演示
- int main(int argc, char *argv[])
- {
- signal(SIGCHLD, SIG_IGN);
- int fd = open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (fd == -1)
- err_exit("file open error");
- cout << "We Don`t flash memory\n";
- char buf[BUFSIZ];
- bzero(buf, sizeof(buf));
- pid_t pid = fork();
- if (pid < 0)
- err_exit("fork error");
- else if (pid > 0)
- {
- strcpy(buf, "Parent...");
- write(fd, buf, strlen(buf));
- close(fd);
- cout << "fd = " << fd << endl;
- exit(0);
- }
- else if (pid == 0)
- {
- strcpy(buf, "Child...");
- write(fd, buf, strlen(buf));
- close(fd);
- cout << "fd = " << fd << endl;
- exit(0);
- }
- }
结果是fd(文件描述符)的值相等。这说明父子进程共享同一个文件描述符,当然文件偏移量等信息也是共享的。
fork与vfork的区别
1. fork子进程拷贝父进程的数据段(但是现在提供了写时复制技术,只有当子进程真正需要写内存时,才复制出该内存的一段副本),因此,在父进程/子进程中对全局变量所做的修改并不会影响子进程/父进程的数据内容.
vfork子进程与父进程共享数据段,因此父子进程对数据的更新是同步的;
2. fork父、子进程的执行次序是未知的,取决于操作系统的调度算法
vfork:子进程先运行,父进程后运行;
3. 如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork,但是你在vfork后执行其它语句却是非常危险的,因为很容易和父进程产生冲突。
- #include <unistd.h>
- #include <stdio.h>
- int main(void)
- {
- pid_t pid;
- int count = 0;
- pid=vfork();
- count++;
- printf("count=%d\n",count);
- return 0;
- }
在学习linux进程编程的时候遇到一个问题,就是使用vfork()函数以后本以为下面会打印出1和2,但是结果却出人意料。
打印出的结果是:
count=1
count=1
Segmentation fault
出现了段错误,经过查证得知,vfork()创建子进程成功后是严禁使用return的,只能调用exit()或者exec族的函数,否则后果不可预料,在main函数里return和exit()效果一样是有前提的:没有调用vfork。
(如果return处什么都没有也会出现段错误,结果如下
count=1
count=9
Segmentation fault
)
Linux进程理解与实践(二)僵尸&孤儿进程 和文件共享的更多相关文章
- Linux进程理解与实践(三)进程终止函数和exec函数族的使用
进程的几种终止方式(Termination) (1)正常退出 从main函数返回[return] 调用exit 调用_exit或者_Exit 最后一个线程从其启动处返回 从最后一个线程调用pthrea ...
- Linux进程理解与实践(四)wait函数处理僵尸进程
Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程 ...
- Linux进程理解与实践(五)细谈守护进程
一. 守护进程及其特性 守护进程最重要的特性是后台运行.在这一点上DOS下的常驻内存程序TSR与之相似.其次,守护进程必须与其运行前的环境隔离开来.这些环境包括未关闭的文件描述符,控制终端, ...
- Linux进程理解与实践(一)基本概念和编程概述(fork,vfork,cow)
进程 and 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...
- !!!!Linux系统开发 系列 4 进程资源 环境 fork()子进程 wait() waitpid()僵尸 孤儿进程
http://990487026.blog.51cto.com/10133282/1834893
- OWIN的理解和实践(二) – Host和Server的开发
对于开发人员来说,代码就是最好的文档,如上一篇博文所说,下面我们就会基于Kanata项目的一些具体调用代码,来进一步深入理解OWIN的实现和作用. 今天我们先针对Host和Server来实现一个简单的 ...
- 进程与线程(二) java进程的内存模型
从我出生那天起,我就知道我有个兄弟,他桀骜不驯,但实力强悍 ,人家都叫它C+++ ----java 上回说到了,C进程的内存分配,那么一个java运行过程也是一个进程,java内 ...
- 二十三、Linux 进程与信号---进程链和进程扇、守护进程和孤儿进程以及僵尸进程
23.1 进程链和进程扇 23.1.1 概念 进程链:一个父进程构建出一个子进程,子进程再构建出子子进程,子子进程构建出子子子进程.... 这种就为进程链 进程扇:一个父进程构建出多个子进程,子进程都 ...
- 【Linux 进程】孤儿进程、僵尸进程和守护进程
1.孤儿进程: 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作.孤儿进程是 ...
随机推荐
- layui 小细节知识点
1.layui-textarea 赋值总是居中 问题 需要 放在同一行 <textarea class="layui-textarea" style="text ...
- 并发王者课-铂金9:互通有无-Exchanger如何完成线程间的数据交换
欢迎来到<并发王者课>,本文是该系列文章中的第22篇,铂金中的第9篇. 在前面的文章中,我们已经介绍了ReentrantLock,CountDownLatch,CyclicBarrier, ...
- 想成为Java高手的25个学习目标
本文将告诉你学习Java需要达到的25个目标,希望能够对你的学习及找工作有所帮助.对比一下自己,你已经掌握了这25条中的多少条了呢? 1.你需要精通面向对象分析与设计(OOA/OOD).涉及模式(GO ...
- 6-x3 declare和typeset命令:设置变量属性
declare 和 typeset 都是 Shell 内建命令,它们的用法相同,都用来设置变量的属性.不过 typeset 已经被弃用了,建议使用 declare 代替.declare 命令的用法如下 ...
- 使用Octotree插件在Edge上以树形结构浏览GitHub上的源码
先预览效果左侧的目录通过点击,就可以到达对应的源码位置. 首先点击打开Edge中的浏览器扩展在右上角...=>点击扩展=>点击获取Microsoft Edge扩展按钮=>在左侧搜索所 ...
- 从新建文件夹开始构建UtopiaEngine(2)
本篇序言 摸了两个月的鱼,又一次拾起了自己引擎的框架,开始完善引擎系统,如果非要用现实中的什么东西比喻的话,那么我们目前实现的框架连个脚手架都不是.把这项目这样晾着显然不符合本人的风格,而且要作为毕业 ...
- MAC系统如果碰到报错信息:sudo:command not found
** 一般要考虑最近是否有别人或者自己修改过环境变量,这种报错往往是因为环境变量设置错误导致的. ** 1. 首先要获得创建,或者是打开bash_profile的权限,请在命令行中输入: export ...
- C语言:float类型%d输出
float类型%d输出 float a=7.5f; 如果用printf("%d",a);输出的是0. 但float型用%d输出是否一定是0呢,答案肯定不都是0: 为什么 7.5 用 ...
- ASP.NET 检测当前计算机及登录用户名
TextBox1.Text = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
- [刘阳Java]_程序员Java编程进阶的5个注意点,别编程两三年还是增删改查
此文章也是关注网上好几篇技术文章后,今天分享出来.因为,总有在程序学习路上的小伙伴会感到迷茫.而迷茫存在的情况如下 第一种:在大学学习中出现的迷茫,不知道Java到底要学什么.学习Java的标准是什么 ...
