96-多进程开发:进程控制

6、进程控制

调用fork函数会创建一个子进程,创建子进程时,并没有将父进程的虚拟地址空间完全拷贝进来;

一开始子进程和父进程是共享虚拟地址空间的,主要共享用户区的数据,内核区的数据还是不一样的,进程id,父进程id都是不同的;(读时共享,写时复制)

6.1 进程退出

状态参数status,会将退出的信息传出;

在父子进程中,子进程退出了,父进程就会的到子进程的退出状态status;

子进程的回收是通过父进程来回收的;子进程退出后,能释放自己用户区的数据,内核区的数据自己是不能释放的。

父进程需要回收子进程内核中的PCB资源.

一般用时,用标准c库的exit()函数。

1、使用exit()函数

/*
    #include <stdlib.h>
    void exit(int status);

    #include <unistd.h>
    void _exit(int status);

    status参数:是进程退出时的一个状态信息。父进程回收子进程资源的时候可以获取到。
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {

    printf("hello\n");
    printf("world");

    exit(0);
    
    return 0;	//exit(0)或者_exit(0)调用成功了,return 0就不会执行了
}

编译运行:

2、使用_exit()函数

/*
    #include <stdlib.h>
    void exit(int status);

    #include <unistd.h>
    void _exit(int status);

    status参数:是进程退出时的一个状态信息。父进程回收子进程资源的时候可以获取到。
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {

    printf("hello\n");
    printf("world");

    _exit(0);
    
    return 0;	//exit(0)或者_exit(0)调用成功了,return 0就不会执行了
}

_exit(), 前面的hello打印出来了,因为\n刷新了I/O缓冲(将内容刷到屏幕上来)

后面的world没有有刷新I/O缓冲,所以world就丢失了。

6.2 孤儿进程

孤儿进程(Orphan Process): 父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就称为孤儿进程。

  • 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init(进程id为1) , 而init进程会循环地wait()它的已经退出的子进程。
  • 这样, 当一个孤儿进程凄凉地结束了其生命周期的时候, init进程就会代表党和政府出面处理它的一切善后工作。
  • 孤儿进程不会有危害。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main() {

    // 创建子进程
    pid_t pid = fork();

    // 判断是父进程还是子进程
    if(pid > 0) {

        printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());

    } else if(pid == 0) {
        sleep(1);	//用来演示僵尸进程,睡一秒钟,父进程早就将自己运行完了
        // 当前是子进程
        printf("i am child process, pid : %d, ppid : %d\n", getpid(),getppid());
        
    }

    // for循环
    for(int i = 0; i < 3; i++) {
        printf("i : %d , pid : %d\n", i , getpid());
    }

    return 0;
}

运行结果:
在这里插入图片描述
在子进程中加入这个:

sleep(1);	//用来演示僵尸进程,睡一秒钟,父进程早就将自己运行完了

此时再编译运行:
在这里插入图片描述
此时子进程的父进程为init进程(进程id为1)

为什么会在向红色那样,切换到前台继续输出?

运行一个程序,默认会切换到后台,当有输出时,会输出到终端;

当父进程死亡后,会切换到前台;(如下)
在这里插入图片描述
但是子进程还没有死,会接着输出。(因为父子进程共享文件描述符表,所以输出的终端是一样的)

6.3 僵尸进程

  • 每个进程结束之后,都会释放自己地址空间中的用户区数据,内核区的 PCB没有办法自己释放掉,需要父进程去释放。
  • 进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
  • 僵尸进程不能被kill -9杀死,
  • 这样就会导致一个问题,如果父进程不调用wait () 或waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main() {

    // 创建子进程
    pid_t pid = fork();

    // 判断是父进程还是子进程
    if(pid > 0) {
        while(1) {
            printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());
            sleep(1);
        }

    } else if(pid == 0) {
        // 当前是子进程
        printf("i am child process, pid : %d, ppid : %d\n", getpid(),getppid());
       
    }

    // for循环
    for(int i = 0; i < 3; i++) {
        printf("i : %d , pid : %d\n", i , getpid());
    }

    return 0;
}

运行结果:

子进程运行完了,父进程一直在循环运行。
在这里插入图片描述
子进程id:14860,父进程id:14859
在这里插入图片描述
可以看到子进程为z,是僵尸进程。

kill -9杀不死僵尸进程;

这里,只能将父进程杀死,子进程会被init进程托管,才能解决,后续会有新的解决方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liufeng2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值