操作系统第三课:进程管理

进程 线程 纤程(面试高频)

面试高频:进程和线程有什么区别?

​ 不专业:进程就是一个程序运行起来的状态,线程是一个进程中的不同的执行路径。

​ 专业:进程是OS分配资源的基本单位,线程是执行调度的基本单位。

分配资源最重要的是:独立的内存空间。线程调度执行(线程共享进程的内存空间,没有自己独立的内存空间)
在这里插入图片描述

进程

在这里插入图片描述

线程

在这里插入图片描述

纤程

纤程fiber:用户态的线程,线程中的线程,切换和调度不需要经过OS

优势:
1:占有资源很少 OS : 线程需要1M Fiber只需要4K空间
2:切换比较简单
3:启动很多个10W+

2020-3-22支持内置纤程的语言:Kotlin Scala Go Python(lib)… Java? (open jdk : loom)

Hotspot目前的线程,每次申请都需要和操作系统打交道,通过内核申请,被称为重量级线程
而纤程的作用是直接和JVM的线程打交道,一个JVM线程可以申请多个纤程,效率会更快
在这里插入图片描述

纤程的实现

​ Java中对于纤程的支持:没有内置,盼望内置

利用Quaser库(不成熟)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>mashibing.com</groupId>
    <artifactId>HelloFiber</artifactId>
    <version>1.0-SNAPSHOT</version>

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

</project>
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.SuspendableRunnable;

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;

        }
    }
}

作业:目前是10000个Fiber -> 1个JVM线程,想办法提高效率,比如10000Fiber -> 10份 -> 10Threads

纤程的应用场景

纤程 vs 线程池:很短的计算任务,不需要和内核打交道,并发量高!

内核线程(了解即可)

内核在启动之后经常需要做一些后台操作,这些由Kernel Thread来完成,只在内核空间运行。
比如 计时、定期清理垃圾

进程的创建和启动

系统函数:系统对外提供的接口
在这里插入图片描述

僵尸进程 孤儿进程

在这里插入图片描述

僵尸进程实验

linux 中 ps命令出来的进程带有< defunct >则为僵尸进程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>

int main() {
    
    
        pid_t pid = fork();

        if (0 == pid) {
    
    
                printf("child id is %d\n", getpid());
                printf("parent id is %d\n", getppid());
        } else {
    
    
                while(1) {
    
    }
        }
}

孤儿进程实验

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>

int main() {
    
    
        pid_t pid = fork();

        if (0 == pid) {
    
    
                printf("child ppid is %d\n", getppid());
                sleep(10);
                printf("parent ppid is %d\n", getppid());
        } else {
    
    
                printf("parent id is %d\n", getpid());
                sleep(5);
                exit(0);
        }
}

进程调度

linux中每个进程都有自己专属的调度方案
在这里插入图片描述
早期的操作系统是单任务(独占CPU),后面逐渐变为多任务(分时占用CPU)
进程调度原则:最大限度的压榨CPU资源

进程调度基本概念

  • 进程类型
    • IO密集型:大部分时间用于等待IO
    • CPU密集型:大部分时间用于闷头计算
  • 进程优先级
    • 实时进程 > 普通进程 (0 - 99)
    • 普通进程nice值(-20 - 19)
  • 时间分配
    • linux采用按优先级的CPU时间比
    • 其他系统多采用按优先级的时间片
  • eg.两个app同时运行
    • 一个文本处理程序
    • 一个影视后期程序

进程调度算法

多任务情况下:

  • 非抢占式(cooperative multitasking) : 除非进程主动让出CPU(yielding),否则将一直运行
  • 抢占式(preemptive multitasking) :由进程调度器强制开始或暂停(抢占)某一进程的执行

Linux的调度策略(选修)

linux2.5 经典Unix O(1)调度策略,偏向服务器,但对交互不友好

linux2.6.23 采用CFS完全公平调度算法Completety Fair Scheduler

CFS:按优先级分配时间片的比例,记录每个进程的执行时间,如果有一个进程执行时间不到他应该分配的比例,优先执行

默认调度策略:
实时进程 (急诊) 优先级分高低 - FIFO (First In First Out),优先级一样 - RR(Round Robin)
普通进程: CFS
在这里插入图片描述

中断

硬件跟操作系统内核打交道的一种机制

软中断(0x80中断信号) == 系统调用

系统调用:int 0x80(老的,在软件层面支持) 或者 sysenter原语(新的,直接在硬件层面支持)
通过ax寄存器填入调用号(对应不同函数)

参数通过bx cx dx si di传入内核
返回值通过ax返回

例子:java读网络 –> jvm read() –> c库read() - > 内核空间 -> system_call() (系统调用处理程序)-> sys_read()

中断处理机制的实现细节
在这里插入图片描述

从汇编角度理解软中断

搭建汇编环境
yum install nasm

;hello.asm
;write(int fd, const void *buffer, size_t nbytes)
;fd 文件描述符 file descriptor - linux下一切皆文件

section data
    msg db "Hello", 0xA
    len equ $ - msg

section .text
global _start
_start:

    mov edx, len
    mov ecx, msg
    mov ebx, 1 ;文件描述符1 std_out
    mov eax, 4 ;write函数系统调用号 4
    int 0x80

    mov ebx, 0
    mov eax, 1 ;exit函数系统调用号
    int 0x80

编译:nasm -f elf hello.asm -o hello.o
链接:ld -m elf_i386 -o hello hello.o
一个程序的执行过程,要么处于用户态,要么处于内核态

猜你喜欢

转载自blog.csdn.net/upset_poor/article/details/123199664