孤儿进程与僵尸进程

孤儿进程:

如果父进程先退出,子进程还没退出那么子进程的父进程将变为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) --僵尸进程与文件共享的更多相关文章

  1. 脚本_查找 Linux 系统中的僵尸进程

    #!bin/bash#功能:查找Linux系统中的僵尸进程#作者:liusingbon#使用awk判断ps命令输出的第8列为Z时,显示该进程的 PID 和进程命令ps aux |awk '{if($8 ...

  2. Linux查找并杀死僵尸进程

    1.查看系统是否有僵尸进程 使用Top命令查找,当zombie前的数量不为0时,即系统内存在相应数量的僵尸进程. 2.定位僵尸进程 使用命令ps -A -ostat,ppid,pid,cmd |gre ...

  3. Linux查找并杀死僵尸进程(转)

    1.查看系统是否有僵尸进程 使用Top命令查找,当zombie前的数量不为0时,即系统内存在相应数量的僵尸进程. 2.定位僵尸进程 使用命令ps -A -ostat,ppid,pid,cmd |gre ...

  4. paip.杀不死进程的原因--僵尸进程的解决.txt

    paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...

  5. [并发编程 - socketserver模块实现并发、[进程查看父子进程pid、僵尸进程、孤儿进程、守护进程、互斥锁、队列、生产者消费者模型]

    [并发编程 - socketserver模块实现并发.[进程查看父子进程pid.僵尸进程.孤儿进程.守护进程.互斥锁.队列.生产者消费者模型] socketserver模块实现并发 基于tcp的套接字 ...

  6. Linux进程实践(5) --守护进程

    概述 守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭:守护进程的名称通常以d结尾,比如sshd.xinetd.crond.atd等 ...

  7. Linux -- 进程管理之僵尸进程

    UNIX 存在一种机制:在每个进程退出的同时,操作系统释放该进程所有资源,但仍然保留一定的信息(PID / Status / runtime),直到父进程执行 wait() / waitpid(),以 ...

  8. 041_查找 Linux 系统中的僵尸进程

    #!/bin/bash#awk 判断 ps 命令输出的第 8 列为 Z 是僵尸进程,显示该进程的 PID 和进程命令 ps aux |awk '{if($8 == "Z"){pri ...

  9. C语言在Linux下创建一个僵尸进程

    第三章编程题3.12 1.僵尸进程是什么 每一个进程都有一个PCB(进程控制块),其中包含进程执行的状态等一系列信息. 当父进程fork()出一个子进程,子进程执行结束后操作系统会回收子进程使用的内存 ...

随机推荐

  1. Docker部署Zabbix+Grafana监控

    Docker部署Zabbix+Grafana监控 环境 centos 7 ; Docker 17.12.0-ce ; docker-compose version 1.20.1 2018-4-1 当前 ...

  2. 两个activity之间透明过渡效果和经验

    来看下效果图: 大致效果解释: 1. 当用户点击登录时logo下滑一定距离 2. 下滑后旋转90时 变化图标 3. 继续旋转90度 4. 然后移动到左上角 透明度渐变到上个activity 最后销毁当 ...

  3. 禁止通过网页URL访问文件夹 asp.net

    我们可以通过如下的两种办法,禁止用户通过浏览器的URL地址直接访问网站服务器的文件夹. 一.通过类和配置文件限制 ①NET C#代码 新建一个类,继承IHttpHandler using System ...

  4. memcached实战系列(四)memcached stats命令 memcached优化

    memcached提供一系列的命令进行优化的查看,方便我们调整我们的存储策略,查看我们的使用率,内存的使用率以及浪费情况.常用的命令有stats.stats settings.stats items. ...

  5. 4.1、Android Stuido配置你的Build Variant

    每个版本的build variant代表了你可以构建的每一个版本.虽然你未直接配置build variants,你可以通过配置build type和product flavor. 比如,一个demo的 ...

  6. UNIX网络编程——原始套接字的魔力【上】

    基于原始套接字编程 在开发面向连接的TCP和面向无连接的UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由TCP或UDP来保证: 也就是说,对于TCP或UDP的程序开发,焦点在Dat ...

  7. 调用MediaScannerConnection 发生内存泄露的解决方法

    调用MediaScannerConnection发起扫描时经常会发生内存泄露,例如: E ActivityThread: Activity FolderListActivity has leaked ...

  8. SSH深度历险(八) 剖析SSH核心原理+Spring依赖注入的三种方式

           在java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依 ...

  9. DAA和CMAC

    数据认证算法(DAA)  Data Authentication Algorithm DAA建立在DES之上,该算法比较陈旧,人们已经发现了这个算法的安全弱点,目前已经被废止. DAA采用DES运算的 ...

  10. python访问redis

    python访问redis 1 Linux上安装redis a) 下载 $ wget http://download.redis.io/releases/redis-3.0.5.tar.gz b) 编 ...