Linux进程实践(2) --僵尸进程与文件共享

简介: 孤儿进程与僵尸进程孤儿进程:   如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。

孤儿进程与僵尸进程

孤儿进程:

   如果父进程先退出,子进程还没退出那么子进程的父进程将变为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;
}

目录
相关文章
|
23天前
|
Linux
Linux下使用ls查看文件颜色全部为白色的解决方法,以及Linux中文件颜色介绍
Linux下使用ls查看文件颜色全部为白色的解决方法,以及Linux中文件颜色介绍
70 2
|
24天前
|
Linux 数据安全/隐私保护 Windows
Linux共享Windows目录
Linux共享Windows目录
|
29天前
|
存储 监控 安全
在Linux中,⼀个EXT3的文件分区,当使用touch test.file命令创建⼀个新文件时报错,报错的信息是提示磁盘已满,但是采用df -h命令查看磁盘大小时,只使用了,60%的磁盘空间,为什么会出现这个情况?
在Linux中,⼀个EXT3的文件分区,当使用touch test.file命令创建⼀个新文件时报错,报错的信息是提示磁盘已满,但是采用df -h命令查看磁盘大小时,只使用了,60%的磁盘空间,为什么会出现这个情况?
|
24天前
|
Linux
Linux 服务器下载百度网盘文件
本教程指导如何使用 `bypy` 库从百度网盘下载文件。首先通过 `pip install bypy` 安装库,接着运行 `bypy info` 获取登录链接并完成授权,最后将文件置于指定目录并通过 `bypy downdir /Ziya-13b-v1` 命令下载至本地。
30 1
Linux 服务器下载百度网盘文件
|
28天前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
13天前
|
算法 调度 UED
操作系统中的进程管理:原理与实践
在数字世界的心脏跳动着无数进程,它们如同细胞一般构成了操作系统的生命体。本文将深入探讨进程管理的奥秘,从进程的诞生到成长,再到最终的消亡,揭示操作系统如何协调这些看似杂乱无章却又井然有序的活动。通过浅显易懂的语言和直观的比喻,我们将一起探索进程调度的策略、同步机制的重要性以及死锁问题的解决之道。准备好跟随我们的脚步,一起走进操作系统的微观世界,解锁进程管理的秘密吧!
24 6
|
17天前
|
Ubuntu Linux Shell
Linux系统命令 安装和文件相关命令
本文档详细介绍了Linux系统中的常用命令,包括软件安装卸载命令如`dpkg`和`apt-get`,压缩与解压命令如`gzip`、`bzip2`和`xz`,以及`tar`命令用于打包和解包。此外还介绍了文件分割命令`split`,文件操作命令如`cat`、`head`、`tail`、`more`、`less`等,管道命令和`wc`、`grep`、`find`、`cut`、`sort`、`uniq`、`diff`等实用工具。最后,文档还讲解了文件属性相关的命令如`chmod`、`chown`、`chgrp`以及创建硬链接和软链接的`ln`命令。
|
22天前
|
监控 算法 调度
探索操作系统中的进程管理:从理论到实践
【8月更文挑战第30天】在数字世界的心脏,操作系统扮演着至关重要的角色。它不仅管理着硬件资源,还确保了软件的顺畅运行。本文将深入探讨操作系统中的一项核心功能——进程管理。我们将从基本概念出发,逐步深入到进程状态、调度算法,以及进程同步机制。通过实际代码示例,我们将看到理论如何转化为实践中的具体操作,从而更好地理解进程管理的精妙之处。无论你是初学者还是有一定基础的开发者,这篇文章都将为你揭开操作系统进程管理的神秘面纱。
|
26天前
|
Linux
linux 删除乱码文件名的文件
【8月更文挑战第26天】当遇到文件名显示为乱码,导致无法正常通过键盘输入文件名进行删除操作时,可以利用鼠标的复制功能配合`rm`命令实现删除。对于文件夹的删除,可使用`rm -rf 目录名`。然而,有时这种方式仍无法删除某些特殊乱码文件,这时可以通过获取文件的i节点号(使用`ls -i`或`ll -i`命令查看)并执行`find -inum [节点号] -delete`来进行删除。这种方法特别适用于处理那些因文件名问题而难以删除的情况。
73 2
|
27天前
|
JSON Linux 网络安全
【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?
【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?