进程与线程

首先,先有一个宏观认识

  1. 进程—是操作系统分配资源的最小单位,操作系统会对每个进程分配内存资源
  2. 线程—是操作系统调度的最小单位,操作系统不会给线程分配资源

进程产生

有之前的编译过程我们知道程序是需要经历 预处理–>编译–>汇编–>链接 才生成可执行文件
在这里插入图片描述

而进程是生成的可执行文件被调度到内存中去,才会由程序变成进程.

简单理解进程是动态的,而程序是静态的.

进程的状态转换

在这里插入图片描述

程序被调度到内存则变成进程进入就绪态,等待获取CPU资源,开始执行;

一旦就绪态的进程获取CPU资源则就会变成执行态的进程;

当CPU给执行态的进程分配的时间片用完, 则进程就会主动释放CPU资源,再次进入就绪队列等待CPU资源;

当执行态的进程被阻塞(如IO等待…等), 则CPU会阻塞进程,进程进入阻塞状态,等待阻塞的事件完成,再次返回就绪队列;

当执行态进程被休眠(sleep()),则CPU会使进程进入休眠队列并释放CPU资源,等待休眠完成,再次返回就绪队列;

当执行态的进程执行完毕 / 被杀死 ,则释放CPU资源,进入僵尸态,此时仅仅释放了CPU资源,其他资源并未回收;

当僵尸态的进程系统资源被完全回收,汇报死亡信息后,则会进入死亡态,此时执行完毕(根据不同的内存调度算法将其他程序调入内存进行覆盖).

多进程

先引入父进程与子进程的概念

fork()

父进程

子进程

父进程通过fork()得到一个子进程

父进程与子进程在初始状态时 整个内存空间, 打开的文件, 工作路径, 进程组, 环境变量, UID和GID都是相同的

进程PID 记录锁 挂起信号不一样

看一下linux的进程树

pstree #查看进程树

在这里插入图片描述

如图,在linux中所有的进程都来自于systemd这个系统进程

所以,运行状态便可以进一步优化
在这里插入图片描述

僵尸进程与孤儿进程

僵尸进程:子进程死亡但是父进程并没有回收子进程资源,子进程就会变成僵尸进程
孤儿进程: 父进程死亡但是子进程并未死亡,则此时子进程会交由systemd管理

来个例子

//僵尸进程
#include <stdio.h>
#include <unistd.h>
// 僵尸进程:子进程死亡但是父进程并没有回收子进程资源, 子进程就会变成僵尸进程
int main () {
    pid_t pid = fork ();    //创建一个子进程
    if (pid == 0) {
        //子进程
        printf ("我是子进程\n");
        sleep (10);  //10s后死亡
        return 0;
    }
    if (pid > 0) {
        while (1) {
            printf ("我是父进程\n");
            sleep (10);
        }
    }
}

可以看到当子程序未死亡时,有两个进程,而子程序死亡后其进程变为defunct
在进程树中其也一直为子进程

:~$ ps -e|grep a.out
  85415 pts/1    00:00:00 a.out
  85416 pts/1    00:00:00 a.out
:~$ ps -e|grep a.out
  85415 pts/1    00:00:00 a.out
  85416 pts/1    00:00:00 a.out <defunct>

:~$ pstree
          systemcd│sh├─bash───a.out───a.out

再来个例子

//孤儿进程
#include <stdio.h>
#include <unistd.h>
// 孤儿进程: 父进程死亡但是子进程并未死亡,则此时子进程会交由systemd管理
int main () {
    pid_t pid = fork ();    //创建一个子进程
    if (pid == 0) {
        //子进程
        while (1) {
            printf ("我是子进程\n");
            sleep (10);  
        }
    }
    if (pid > 0) {
        printf ("我是父进程\n");
        sleep (10);
        return 0;
    }
}

输出

:~$ ./a.out 
我是父进程
我是子进程
我是子进程
:~$ 我是子进程  #这里父进程已经退出但是子进程并没有结束所以
我是子进程

进程树

:~$ pstree |grep a.out
    systemcd|  sh |-bash---a.out---a.out 
:~$ pstree |grep a.out
    systemcd|     |-a.out

再父进程没有结束时子进程属于父进程,父进程终止后子进程变成孤儿进程被systemcd管理

孤儿进程并非一定是需要避免的 我们可以利用这一个特性,在一些需要让操作系统进行管理,在后台默默执行的东西,比如挖矿(不可取,进橘子) ,比如ssh,mysql的服务.

如何避免尸进程与孤儿进程

wait 回收进程资源防止僵尸和孤儿进程的产生!

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main () {
    pid_t pid = fork ();    //创建一个子进程
    if (pid == 0) {
        //子进程
        int i = 0;
        while (i < 2) {
            printf ("我是子进程\n");
            sleep (10);
            i++;
        }
    }
    if (pid > 0) {
        printf ("我是父进程\n");
        int status;
        wait (&status);     //等待回收进程
        printf ("进程回收完毕\n");
        return 0;
    }
}
:~$ ./a.out 
我是父进程
我是子进程
我是子进程
进程回收完毕
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐