Linux进程实践(2) --僵尸进程与文件共享
孤儿进程与僵尸进程
孤儿进程:
如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)
//生成孤儿进程
int main(int argc, char *argv[])
{
pid_t pid = fork();
if (pid < 0)
err_exit("fork error");
else if (pid > 0)
exit(0);
else
{
sleep(10);
cout << "Child, ppid = " << getppid() << endl;
}
exit(0);
}
僵尸进程:
如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵尸进程。
//生成僵尸进程
int main(int argc, char *argv[])
{
pid_t pid = fork();
if (pid < 0)
err_exit("fork error");
else if (pid == 0)
exit(0);
else
{
sleep(50);
}
exit(0);
}
附-查询父子进程状态
ps -le | grep main
避免僵尸进程
signal(SIGCHLD, SIG_IGN);
//示例: 避免僵尸进程
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);
}
}
fork VS vfork
在UNIX/Linux中的fork还没实现copy on write(写时复制)技术之前。Unix设计者很关心fork之后立刻执行exec所造成的地址空间浪费,所以引入了vfork系统调用。其中,vfork子进程与父进程共享数据段,并不真正复制父进程内存,因此在vfork之后执行exec系列函数,并不会导致地址空间浪费以及无用的空间复制时间.而且,即使fork实现了copy on write,效率也没有vfork高.
但是,vfork有个限制,子进程必须立刻执行_exit或者exec系列函数。因此我们不推荐使用vfork,因为几乎每一个vfork的实现,都或多或少存在一定的问题(可以尝试在vfork之后的子进程中既不执行_exit,也不执行exec函数)。
fork与vfork的区别
1. fork子进程拷贝父进程的数据段(但是现在提供了写时复制技术,只有当子进程真正需要写内存时,才复制出该内存的一段副本),因此,在父进程/子进程中对全局变量所做的修改并不会影响子进程/父进程的数据内容.
vfork子进程与父进程共享数据段,因此父子进程对数据的更新是同步的;
2. fork父、子进程的执行次序是未知的,取决于操作系统的调度算法
vfork:子进程先运行,父进程后运行;
//示例1:vfork出错情况
//在Linux 2.6内核上会持续执行,不会退出
//而在Linux 3.13内核上, 则会引发core dump
int main()
{
int iNumber = 0;
pid_t pid = vfork();
if (pid == -1)
{
perror("fork");
return -1;
}
else if (pid > 0)
{
cout << "In Parent Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
//_exit(0);
}
else if (pid == 0)
{
iNumber ++;
cout << "In Child Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
//_exit(0);
}
return 0;
}
//示例2: 父进程/子进程修改全局数据的情况
int main()
{
int iNumber = 10;
cout << "Before vfork, pid = " << getpid() << endl;
//对比fork()
pid_t pid = vfork();
if (pid == -1)
err_exit("fork");
else if (pid > 0)
{
sleep(4);
cout << "Parent, iNumber: " << iNumber << endl;
}
else if (pid == 0)
{
++ iNumber;
cout << "Child, iNumber = " << iNumber << endl;
_exit(0);
}
return 0;
}
//示例3:用vfork执行当前目录下的hello程序
int main()
{
int iNumber = 0;
pid_t pid = vfork();
if (pid == -1)
{
perror("fork");
return -1;
}
else if (pid > 0)
{
cout << "In Parent Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
}
else if (pid == 0)
{
iNumber ++;
cout << "In Child Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
//将自己写的程序启动起来
execve("./hello",NULL,NULL);
_exit(0);
}
return 0;
}
//测试4,用vfork执行系统命令
int main()
{
int iNumber = 0;
pid_t pid = vfork();
if (pid == -1)
{
perror("fork");
return -1;
}
else if (pid > 0)
{
cout << "In Parent Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
}
else if (pid == 0)
{
iNumber ++;
cout << "In Child Program..." << endl;
cout << "iNumber = " << iNumber << endl;
cout << "pid = " << static_cast<int>(getpid());
cout << "\t ppid = " << static_cast<int>(getppid()) << endl;
//将ls命令启动起来,注意:由于C++严格的类型转换机制,需要在字符串前加(char*)
char *const args[] = {(char *)"/bin/ls", (char *)"-l", NULL};
int res = execve("/bin/ls",args,NULL);
if (res == -1)
{
perror("execve");
_exit(1);
}
_exit(0);
}
return 0;
}
Linux进程实践(2) --僵尸进程与文件共享的更多相关文章
- 脚本_查找 Linux 系统中的僵尸进程
#!bin/bash#功能:查找Linux系统中的僵尸进程#作者:liusingbon#使用awk判断ps命令输出的第8列为Z时,显示该进程的 PID 和进程命令ps aux |awk '{if($8 ...
- Linux查找并杀死僵尸进程
1.查看系统是否有僵尸进程 使用Top命令查找,当zombie前的数量不为0时,即系统内存在相应数量的僵尸进程. 2.定位僵尸进程 使用命令ps -A -ostat,ppid,pid,cmd |gre ...
- Linux查找并杀死僵尸进程(转)
1.查看系统是否有僵尸进程 使用Top命令查找,当zombie前的数量不为0时,即系统内存在相应数量的僵尸进程. 2.定位僵尸进程 使用命令ps -A -ostat,ppid,pid,cmd |gre ...
- paip.杀不死进程的原因--僵尸进程的解决.txt
paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...
- [并发编程 - socketserver模块实现并发、[进程查看父子进程pid、僵尸进程、孤儿进程、守护进程、互斥锁、队列、生产者消费者模型]
[并发编程 - socketserver模块实现并发.[进程查看父子进程pid.僵尸进程.孤儿进程.守护进程.互斥锁.队列.生产者消费者模型] socketserver模块实现并发 基于tcp的套接字 ...
- Linux进程实践(5) --守护进程
概述 守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭:守护进程的名称通常以d结尾,比如sshd.xinetd.crond.atd等 ...
- Linux -- 进程管理之僵尸进程
UNIX 存在一种机制:在每个进程退出的同时,操作系统释放该进程所有资源,但仍然保留一定的信息(PID / Status / runtime),直到父进程执行 wait() / waitpid(),以 ...
- 041_查找 Linux 系统中的僵尸进程
#!/bin/bash#awk 判断 ps 命令输出的第 8 列为 Z 是僵尸进程,显示该进程的 PID 和进程命令 ps aux |awk '{if($8 == "Z"){pri ...
- C语言在Linux下创建一个僵尸进程
第三章编程题3.12 1.僵尸进程是什么 每一个进程都有一个PCB(进程控制块),其中包含进程执行的状态等一系列信息. 当父进程fork()出一个子进程,子进程执行结束后操作系统会回收子进程使用的内存 ...
随机推荐
- java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet
解决此异常的方法是: 删除您添加在Referenced Libraries 下的catalina.jar包, 然后删除Webapp下的部署程序,重新部署后一切正常. ? --------------- ...
- 智能指针之 unique_ptr
对于动态申请的内存,C++语言为我们提供了new和delete运算符, 而没有像java一样,提供一个完整的GC机制,因此对于我们申请的动态内存, 我们需要时刻记得释放,且不能重复释放,释放后不能再去 ...
- 利用Python进行数据分析——Numpy基础:数组和矢量计算
利用Python进行数据分析--Numpy基础:数组和矢量计算 ndarry,一个具有矢量运算和复杂广播能力快速节省空间的多维数组 对整组数据进行快速运算的标准数学函数,无需for-loop 用于读写 ...
- Linux 虚存 linux2.6内核特性
一.大型页面的支持 当代计算机体系结构大都支持多种页面大小,例如,IA-32体系结构支持4KB或4MB的页面, Linux操作系统只是将大型页面用于映射实际的内核映像.大型页面的使用主要是为了改进高性 ...
- 学习笔记:Zookeeper 应用案例(上下线动态感知)
1.Zookeeper 应用案例(上下线动态感知) 8.1 案例1--服务器上下线动态感知 8.1.1 需求描述 某分布式系统中,主节点可以有多台,可以动态上下线 任意一台客户端都能实时感知到主节点服 ...
- 在vs2013上的编译tesseract-ocr
在vs2013上的编译tesseract-ocr OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程. Tesserac ...
- 自定义Java注解的方式与应用
注解的作用 Annotation(注解)是JDK 5.0引入的特性,它的基本作用就是修饰编程元素. 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记.编译器.开发工具或其他程序可以用反射 ...
- 机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾
作者:寒小阳 && 龙心尘 时间:2015年11月. 出处: http://blog.csdn.net/han_xiaoyang/article/details/49797143 ht ...
- 文件操作:fseek函数和ftell函数
1.fseek函数: int fseek(FILE * _File, long _Offset, int _Origin); 函数设置文件指针stream的位置.如果执行成功,stream将指向以fr ...
- Android初级教程获取手机系统联系人信息
在手机内部,对联系人信息存在对应的数据库.我们创建的而联系人信息都存在这张表中.如下是对数据库的截图,我已经对表和应该注意的地方做了红笔标注: 好了,现在可以根据数据库里面的数据来写代码了. 代码如下 ...