3、进程管理

进程 线程 纤程

常见面试题:进程和线程的区别?
答:进程就是一个程序运行起来的状态,线程是进程里面不同的执行路径。
专业角度:进程是操作系统分配资源的基本单位,线程是执行调度的基本单位。分配资源最重要的是独立的内存空间,线程调度执行。(线程共享进程的内存空间,线程没有自己的内存空间
所以就是:一个程序中是可以有多个进程的,一个进程中有多个线程,一个线程中有多个纤程。

linux中进程称为task,是系统分配资源的基本单位。
进程描述符:PCB(Process Control Block)称之为进程的类型结构

进程创建和启动

系统函数:Linux系统是由C写的,C提供的一个函数(fork()),调用这个fork()函数就启动了一个进程,调用exec()就执行这个进程。
fork()函数里面还是调用的clone()函数,如果从A进程fork()一个B进程,那么B进程就是A进程的子进程

僵尸进程

ps -ef |grep defuct
父进程产生子进程以后,会维护子进程的一个PCB结构,子进程退出,父进程就释放,如果父进程没有释放,子进程就是僵尸进程。
就是说 子进程已经销毁,但是父进程没有删除子进程的PCB

孤儿进程

子进程还没完成执行完,但是父进程已经销毁。
会有一个特殊的进程来专门给孤儿进程分配一个父进程。

进程调度(任务调度)

从单任务(独占)到多任务(分时)

  • 单任务:比如早期的DOS命令模式的windows系统,都是单任务的,一个系统只能干一件事,干多件事必须要切换,不然系统就直接死了。

  • 多任务

    • 非抢占式:除非进程主动让出cpu,否则就一直执行
    • 抢占式: 进程调度器强制开始或暂停,抢占某一进程的执行

进程调度
2.6采用CFS调度策略:Completely Fair Scheduler
按优先级分配时间片的比例,记录每个进程的执行时间,如果有一个进程执行时间不到他应该分配的比例,优先执行

默认调度策略
实时 (急诊) 优先级分高低 - FIFO (First In First Out),优先级一样 - RR(Round Robin)
普通: CFS

纤程

表示线程中的线程,就是说是用户空间的线程,为什么要有纤程呢?
如下图:拿JVM来做比较,JVM本身也是一个进程,只不过有点意思的是跑在操作系统中的操作系统,
JVM中的线程是对应着操作系统中的线程,每次执行线程(JVM的线程,也就是用户态的)最终都是经过操作系统的线程(也就是内核态)执行的,中间不停的用户态和内核态切换。
但是纤程是在线程中又分配的多个线程,这是纯在用户态执行的线程,称为纤程。可以根本不执行到操作系统的线程,因为它是基于在线程中的,也就是用户态的。
比如操作系统的内核执行几十万个线程,可能会很卡,因为中间不停的切换用户态内核态,但是纤程是在用户空间的,所以线程中有几十万的纤程,也不会影响到切换形态。

所以总之就是一句话,纤程就是跑在用户态的线程。好处就是不用切换形态,占用资源很少,所以纤程切换比较简单,也能启动非常多!

目前2020 3 22支持内置纤程的语言:Kotlin Scala Go Python(lib)...

测试纤程用例

利用Quaser库(不成熟)
依赖:

		<!-- https://mvnrepository.com/artifact/co.paralleluniverse/quasar-core -->
        <dependency>
            <groupId>co.paralleluniverse</groupId>
            <artifactId>quasar-core</artifactId>
            <version>0.8.0</version>
        </dependency>

使用线程执行这段逻辑:

public class HelloFiber {
    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        Runnable r = new Runnable() {
            @Override
            public void run() {
                calc();
            }
        };
        int size = 10000;
        Thread[] threads = new Thread[size];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(r);
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }
        for (int i = 0; i < threads.length; i++) {
            threads[i].join();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    static void calc() {
        int result = 0;
        for (int m = 0; m < 10000; m++) {
            for (int i = 0; i < 200; i++) result += i;
        }
    }
}

使用纤程执行这段逻辑:

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.SuspendableRunnable;

public class HelloFiber2 {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();


        int size = 10000;

        Fiber<Void>[] fibers = new Fiber[size];

        for (int i = 0; i < fibers.length; i++) {
            fibers[i] = new Fiber<Void>(new SuspendableRunnable() {
                public void run() throws SuspendExecution, InterruptedException {
                    calc();
                }
            });
        }

        for (int i = 0; i < fibers.length; i++) {
            fibers[i].start();
        }

        for (int i = 0; i < fibers.length; i++) {
            fibers[i].join();
        }

        long end = System.currentTimeMillis();
        System.out.println(end - start);


    }

    static void calc() {
        int result = 0;
        for (int m = 0; m < 10000; m++) {
            for (int i = 0; i < 200; i++) result += i;

        }
    }
}

对比这两个类的执行效率,可以明显看到差别,并且还有再次优化,使用多个线程来分担。

纤程的应用场景

很短的计算任务,不需要和内核打交道,并发量高!

中断

硬件跟操作系统内核打交道的一种机制
软中断:(80中断) == 系统调用
系统调用:int 0x80(之前老的) 或者 sysenter原语(现在新的)
通过ax寄存器填入调用号
参数通过bx cx dx si di传入内核
返回值通过ax返回

比如:按下键盘,这个按键指令交给了 中断控制器,到达了CPU以后,CPU让内核中固定的一个专门处理中断的程序, 去让操作系统执行中断程序,处理的时候分上半场 和 下半场,上半场是内核内部处理的,下半场指的是应用程序的处理(比如Offce)。
image

posted @ 2021-12-13 14:32  aBiu--  阅读(46)  评论(0编辑  收藏  举报