OS之《线程管理》
进程是系统资源分配的最小单位,线程是最小的执行单位。
然而,现在的高级设计底层还是基于这个理论基础实现的。比如java的线程,还有最新版本的JDK的协程都是在为了更好的让CPU执行任务。
线程是为了使用多CPU提高笑了
为什么一定要使用线程?
- 线程是处理机调度的基本单位。cpu进行任务调度的时,进程需要现场保护,保存大量的寄存器的数据,而线程只需要保护少数寄存器的数据。
- 并发性。一个进程中的多个线程是可以并发执行。更快
- 拥有资源。进程是作为资源分配的基本单位。pcb创建时,申请了需要的所有资源,当然这些资源在线程中是可以共享的。线程不需要拥有所有资源,子需要有能保证线程独立运行的资源就好。比如:TCB,程序计数器,状态参数和返回地址等响应的寄存器和堆栈。所有线程能共享进程拥有的IO设备、信号量、内存空间、打开的文件等资源
- 独立性。进程管理中,进程是独立的。独立运行,独立的内存空间地址等。但线程中更多的是共享。多线程多数是为了配合更快的完成任务。
- 系统开销。线程的创建比进程快50倍,线程的切换快5倍。因为多个线程具有相同的地址空间(进程的地址),所以线程的通信也要快并且简单。很多OS中线程的切换、同步、通信不需要OS内核干预。
- 多处理机并行执行。
线程三态:执行、就绪、阻塞
线程控制块TCB都包含哪些内容
- thread表示符
- 一组寄存器,包含程序计数器、状态寄存器、通用寄存器
- 线程运行状态
- 优先级
- 线程专有存储区域,用于线程切换的时现场保护使用
- 信号屏蔽
- 堆栈指针。每一个线程设置一个堆栈用于保存方法调用过程中,局部变量和返回地址。在TCB中必须设置两个指针。一个执行用户堆栈指针,一个执行核心栈指针。当前程序运行在用户太态时,使用用户自己的堆栈保持局部变量和返回地址。当陷入内核态时,使用内核态的栈保存局部变量和返回地址。
多线程操作系统中的进程属性
- 进程是拥有资源的基本单位。除了拥有打开的设备、文件等资源外,还有一张由核心进程维护的地址映射表,该表用于实现用户程序的逻辑地址和物理地址映射关系。
- 多线程可以并发执行。java就是最典型的例子。
- 进程不再是可执行的实体。线程才是可执行的最小单元。但是os对进程的操作会对进程中的线程起作用。比如对进程执行挂起时,会将进程中的所有线程全部挂起。os把进程激活时,会把该进程中的所有线程也激活。
线程的实现方式由两种
- 内核级线程:不论进程还是线程,都是通过内核控制其创建,阻塞,撤销,切换的,为了实现oS对其控制, 所以会每一个线程对应的TCB或者是PCB进行调度的。这种实现方式有以下优势:
- 在多处理机下,内核能同时调度同一进程中的多个线程到处理机并行执行。
- 如果进程中的一个线程被阻塞了,内核还可以调用该进程中的其他线程到处理机运行
- 内核支持线程具有很小的数据结构和堆栈。线程的切换快,开销小。
- 内核本省也可以使用多线程技术
- 它的明显的缺点是:对用户线程来讲,线程的切换,调度等开销比较大,是因为变态导致的。
- 用户级线程:用户级线程是在用户空间下实现的。对应的线程的创建、撤销、同步、通信等功能都是在用户态实现的,不需要os内核参与,既用户级线程是和内核无关的。这些TCB都是在用户态存在的,线程所执行的操作也不需要内核干预,因而内核是感受不到用户线程的存在的。优势如下:
- 线程在用户空间下进行切换,创建,撤销等一系列操作,是不需要切换到内核态的。因为一个用户太的进程拥有了该进程下是所有的线程TCB的,在用户太就能完成调度和管理。从而减小的开销
- 调度算法可以是进程专用的。在不干扰OS调度的情况下,不同的进程可以根据选择的不同的调度算法,对自己的线程进程管理和调度,和OS的低级调度算法无关。
- 用户级线程的实现和OS无关,因为对线程的管理的代码是属于用户程序的一部分,所有的应用程序都可以对之进行共享。可以理解是一个特定的接口,具体实现是有各个应用自己去实现的。因此,用户级线程甚至可以在不支持线程机制的操作系统平台上实现。
用户级线程的缺点也很明显
- 如果遇到基于进程机制的OS中,大多数的系统调用会将进程阻塞,因此,当一个线程执行一个系统调用的时候,不仅该线程会被阻塞,整个进程内的所有线程都会阻塞。而在内核支持线程的方式中,该进程中的其他线程还是可以继续运行的。
- 在单纯的用户级线程实现方式中,多线程应用不能利用多处理机。内核每次给进程分配一个cpu,因此进程中只有一个线程能执行,其他只能等待。
组合方式:
把用户多线程和内核多线程结合起来。就会出现n:N的关系。当发生系统调用的时候,就会将用户线程和内核线程进行映射。内核控制线程的数据可以根据应用进程和系统的不同而变化
线程的实现方式:
-
内核支持线程的实现
内核支持以直接使用系统调用,操作简单。
-
用户级线程的实现
所有用户级线程都有一个相同的结构,他们是在一个中间系统上现。现在有两种中间系统实现。线程的调度执行也很简单,只需要有对应的栈指针和程序计数器就可以完成线程执行。运行时系统:它是一个控制线程对系统函数调用时的控制,有这么一个运行时系统,将对系统调用的函数包装一下,放在用户态空间下,用户线程在调用的时候不需要变态等操作,隔离了对内核态的依赖。使得用户线程和内核无关。
内核控制线程:它是一种轻型进程(LWP,light weight process),每一个进程都可以拥有多个lwp,同用户级线程一样,都有自己的TCB,其中包括有线程标识,优先级,状态,还有栈和局部存储区等。LWP可以共享进程所拥有的资源。它可以通过系统调用来获得内核提供服务。这样,当一个用户级别线程只要和一个LWP连接,就能过去的内核对支持。一个系统中用户级线程可能很多,不可能实现每一个线程都有一个LWP和其对应,就对LWP做了池化管理。用户级线程只要能连接上池中的任意线程,就能实现对内核的调用。这样也一定程度上实现了多路复用一个LWP。用户可以通过LWP连接到内核,但内核只能看到LWP,看不到用户级线程。也实现了用户线程和内核线程之间的隔离。
本文来自博客园,作者:Eular,转载请注明原文链接:https://www.cnblogs.com/euler-blog/p/18599994
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了