父子进程、僵尸进程和孤儿进程

本文是接着进程的状态_土豆西瓜大芝麻的博客-CSDN博客往后验证的,这里也顺便验证了一下僵尸进程和孤儿进程。

父进程与子进程

在Linux里,除了进程0(即PID=0的进程)以外的所有进程都是由其他进程使用系统调用fork创建的,这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程。

fork函数包含在unistd.h库中,其最主要的特点是,调用一次,返回两次,当父进程fork()创建子进程失败时,fork()返回-1,当父进程fork()创建子进程成功时,此时,父进程会返回子进程的pid,而子进程返回的是0。

如上图所示,当fork()函数调用后,父进程中的变量pid赋值成子进程的pid(pid>0),所以父进程会执行else里的代码,打印出"This is the parent",而子进程的变量pid赋值成0,所以子进程执行if(pid == 0)里的代码,打印出"This is the child"

现在我们知道,在Linux中,正常情况下,子进程是通过父进程创建的,子进程再创建新的子进程。但是子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

1. 僵尸进程

当一个子进程结束运行(一般是调用exit、运行时发生致命错误或收到终止信号所导致)时,子进程的退出状态(返回值)会回报给操作系统系统则以SIGCHLD信号将子进程被结束的事件告知父进程,此时子进程的进程控制块(PCB)仍驻留在内存中。一般来说,收到SIGCHLD后,父进程会使用wait系统调用(需要人为增加相应代码)以获取子进程的退出状态,然后内核就可以从内存中释放已结束的子进程的PCB;而如若父进程没有这么做的话(没有增加wait()等调用语句),子进程的PCB就会一直驻留在内存中,也即成为僵尸进程。简单来说,当进程退出但是父进程并没有调用wait或waitpid获取子进程的状态信息时就会产生僵尸进程。

在linux下,使用fork()派生出来的子进程和父进程同名,按照网上的说的使用prctl()设置进程名的方式在子进程中设置,发现只有在子进程死后或者变成僵尸进程时,才会显示其被prctl()设置的名字。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/prctl.h>


int main()
{
    int cnt = 0;
    pid_t pid = fork();
    if(pid>0)
    {
        printf("Parent Proccess!\n");
    }
    else if(pid == 0)
    {
        prctl(PR_SET_NAME,"ps_stat_Child",NULL,NULL,NULL);//设置子进程的名字,这里已经超过16个字符了,实际只能使用16个字符。
        printf("你好!\n");
        sleep(50);
        exit(0);
    }
    while(1)
    {
        printf("hello world #%d\n",cnt++);
        sleep(1);
    }
    return 0;
}

上述例子中,子进程先结束,父进程不结束,那么使用ps -aux查看进程状态,发现刚开始俩进程都在运行,名字也相同,都是前台进程。

 

 但是等到子进程结束后(等待50s后),子进程变成僵尸进程,而此时子进程的名字变为设置的名字。

2. 孤儿进程

 孤儿进程由于有init进程循环的wait()回收资源,因此并没有什么危害。

 使用ps -ef 查看进程间的关系,可以看到进程9813的父进程是9812,而9812的父进程是7324。7324的父进程是7315 对应的bash进程,bash进程的父进程是1150对应的/usr/libexec/gnome-terminal-server,1150的父进程是1号进程。

 在父子进程都在执行过程中(sleep中),两个进程都是前台进程,状态为S+。

 父进程结束后,子进程9813的父进程变成了1150.

 查看进程1150的父进程为1.

 父进程结束后,子进程处于S状态(因为是sleep操作)。

 只剩下子进程后,子进程被系统接管,此时变成后台进程,状态为S(因为在执行sleep)。

 3. 避免出现僵尸子进程

避免僵尸进程的方式有好几种,这里只给出使用wait()方式。

Wait函数
头文件:  #include <sys/types.h>      

                #include <sys/wait.h>

功能:父进程一旦调用了wait函数就立即阻塞自己,wait函数自动分析是否当前进程的某子进程已经退出,如果让它找到一个已经僵尸的子进程,wait就收集这个子进程的信息,并把它彻底销毁后返回,如果没有找到就一直阻塞到这里,直到一个出现为止。Wait函数处理了僵尸子进程。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int cnt = 0, status;
    pid_t pid = fork();
    if (pid > 0) //父进程
    {
        printf("Parent Proccess!\n");
        sleep(50);
    }
    else if (pid == 0)//子进程
    {
        prctl(PR_SET_NAME, "ps_stat_Child", NULL, NULL, NULL);
        printf("你好!\n");
        sleep(20);
        exit(0);
    }
    else
    {
        printf("Parent !\n");
        wait(&status);//阻塞并接受子进程退出状态码
        printf("status = %d\n", status);
    }
    // while(1)
    // {
    //     printf("hello world #%d\n",cnt++);
    //     sleep(1);
    // }
    return 0;
}

子进程退出后,并没有变成僵尸进程。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,可以使用`multiprocessing`模块来创建子进程,并且通过进程间通信(IPC)来实现它们之间的通讯。下面是一个简单的示例: ```python from multiprocessing import Process, Pipe # 定义一个函数作为子进程的任务 def child_task(conn): # 子进程通过连接发送消息给进程 conn.send("Hello from child process!") # 接收进程发送的消息 message = conn.recv() print("Child process received:", message) # 关闭连接 conn.close() if __name__ == '__main__': # 创建一个管道,用于进程间通信 parent_conn, child_conn = Pipe() # 创建子进程,传入管道连接 child_process = Process(target=child_task, args=(child_conn,)) # 启动子进程 child_process.start() # 进程通过连接接收子进程发送的消息 message = parent_conn.recv() print("Parent process received:", message) # 进程通过连接发送消息给子进程 parent_conn.send("Hello from parent process!") # 等待子进程结束 child_process.join() ``` 在上面的示例中,我们使用`Pipe`函数创建了一个双向管道,然后将管道的一端传递给子进程子进程通过连接发送消息给进程,并且接收进程发送的消息。进程也可以通过连接接收子进程发送的消息,并且发送消息给子进程。最后,我们使用`join`方法等待子进程结束。 这只是一个简单的示例,实际上,Python中还有其他的进程间通信方式,如使用`Queue`、`Manager`等。你可以根据具体的需求选择适合的方式来实现进程间通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值