聊聊线程技术与线程实现模型

本文探讨了线程的基本概念及其重要性,并详细分析了三种常见的线程模型:用户空间线程模型、内核空间线程模型以及内核用户空间线程模型。每种模型的特点与适用场景均有所涉及。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

聊聊线程技术与线程实现模型

线程定义

什么是线程?《POSIX Threads Programming》中有一段话对线程的定义进行描述:

A thread is defined as an independent stream of instructions that can be scheduled to run as such by the operating system.

线程可以被认为是一个可以被独立调度的实体,这个实体共享进程的地址空间、文件描述符、代码和数据,且拥有自己私有的栈、寄存器上下文、和程序计数器。

为什么要线程

我们在 github 上面给开源项目提交代码的时候,按照 comment 格式都要写 Motivation 这部分,我们今天讨论线程这个存在,也要讨论线程为什么存在。

在很多应用中需要同时执行多个任务,这些任务大部分甚至全部都可以相互独立的并行的执行。比如一个网络代理,传统的实现是用一个进程作为监听器来监听网络端口,当有客户端连接进来的时候,当前进程将会 fork 一个新的进程来处理客户端的请求。这种体系结构不好的地方如下:

  • fork 系统调用对于操作系统来说是一个非常重的操作
  • 每一个进程都有自己独立的地址空间,进程间相互通信必须要通过标准的 IPC 技术来实现,比如信号量、共享内存,这些操作是非常昂贵的、严重影响系统性能。

线程的出现就是为了解决这些问题,线程之间拥有共享的进程空间用于共享数据、也有自己独立的运行空间类似一个轻量级的进程

用户空间与内核空间

在理解用户线程与内核线程之前、我们有必要了解一下用户空间与内核空间。现代操作系统的地址空间主要基于虚拟地址空间机制设计,和实际物理内存大小没关系,比如对于 32 位操作系统,它的寻址空间为 2 的 32 次方也就是 4G,这里的寻址空间被称为虚拟存储空间。操作系统的核心是内核,独立于普通应用程序,具有最高权限,可以访问底层硬件设备以及受保护的空间,因此这部分包括驱动程序和操作系统。操作系统的设计者为了保证内核的安全,将用户进程设计为只有一定权限的程序,它不能够操作内核以及硬件。操作系统将虚拟存储空间划分为两部分,一部分是内核空间,一部分是用户空间。针对 Linux 操作系统而言,最高的 1G 字节供内核使用,称为内核空间,较低的 3G 字节供给各个进程使用,被称为用户空间。进程可以通过系统调用进入内核,Linux 内核由所有进程共享。用户空间和内核空间示意图如下:

用户空间及内核空间

用户态与内核态

每个进程都拥有所有的虚拟地址空间,当进程运行用户代码的时候是运行在用户地址空间的,这时候 CPU 运行所需要的指令和数据都保存在用户空间,进程可以认为是指令 + 数据 + CPU,因此这个时候我们把这个状态的进程叫做用户进程。当用户执行系统调用而陷入内核代码中执行的时候,当前进程运行的指令和数据都在内核空间,因此我们把这个状态的进程叫内核进程。用户进程和内核进程不是独立的两个进程的意思,而是进程运行的不同状态值得注意的是,用户进程不能访问内核虚拟地址空间,内核进程可以访问全部的虚拟地址空间,因此用户进程和内核进程进行数据交换只能通过内核进程从用户地址空间取数据,然后放入用户地址空间

系统调用涉及到进程从用户态到内核态的切换(mode switch),这个时候涉及到的切换主要是寄存器上下文的切换,和通常所说的进程上下文切换不同,mode switch 的消耗相对要小很多。

用户线程与内核线程

上面可以看出,用户线程与内核线程的区别主要在于指令与数据运行于不同虚拟地址空间,用户线程和内核线程也可以叫做用户空间线程和内核空间线程。用户线程由用户代码支持,内核线程由操作系统内核支持。

线程上下文切换

线程上下文切换和线程模态切换不是一个维度的东东,线程上下文切换讲的是多线程之间因为调度器的调度,而从一个线程正在被调度切换到另外一个线程被调度的事情。线程上下文切换必须要保存线程执行的寄存器状态、栈信息、线程正文、数据等,因此相对模态切换是比较重的操作。

线程模型

线程模型在不同的操作系统下的实现通常有三种,每种模型都有其优点与缺点,下面我们来看看这三种线程模型。

用户空间线程模型(M : 1)

一个多线程子系统有可能全部由用户代码实现,这些线程的调度与切换全部发生在用户地址空间,这种模型通常是由一个内核线程和多个用户线程组成。典型的实现是基于 POSIX 线程 draft 4,OSF’DCE 是其中一种具体实现。一个用户空间库负责线程的创建、终止、调度与同步。这些线程对于操作系统内核是透明的。

这种模型的好处是线程上下文切换都发生在用户空间,避免的模态切换(mode switch),从而对于性能有积极的影响。然而不好的地方是所有的线程基于一个内核调度实体即内核线程,这意味着只有一个处理器可以被利用,在多处理环境下这是不能够被接受的,本质上,用户线程只解决了并发问题,但是没有解决并行问题。

还有一点,如果线程因为 I/O 操作陷入了内核态,内核态线程阻塞等待 I/O 数据,则所有的线程都将会被阻塞,用户空间也可以使用非阻塞而 I/O,但是还是有性能及复杂度问题。

用户空间线程模型

内核空间线程模型(1:1)

对于用户空间线程模型,所有的用户线程都和特定的内核线程进行交互,而内核空间线程模型是每个用户线程都和一个特定的内核线程进行交互,用户线程和内核线程是 1:1 的关系。典型的实现是将每个用户线程映射到一个内核线程上。

每个线程由内核调度器独立的调度,所以如果一个线程阻塞则不影响其他的线程。然而,创建、终止和同步线程都会发生在内核地址空间,这可能会带来较大的性能问题。在创建线程的时候内核必须要进行内存锁的申请,并负责调度线程,而且每个线程都要消耗有限的内核资源,当大量的线程被创建的时候,体现的尤为明显。值得夸奖的是,在多核处理器的硬件的支持下,内核空间线程模型支持了真正的并行,下面是内核空间模型示意图:

内核空间线程模型

内核用户空间线程模型(M : N)

内核用户空间线程模型中,内核线程和用户线程的数量比为 M : N,因此也通常被叫做 M : N 线程模型,内核用户空间综合了前两种的优点。

这种模型需要内核线程调度器和用户空间线程调度器相互操作,本质上是多个线程被绑定到了多个内核线程上,这使得大部分的线程上下文切换都发生在用户空间,而多个内核线程又可以充分利用处理器资源,模型图如下:

内核用户空间线程模型

总结

最近在做 jvm 线程实现相关研究,发现 java 线程的问题其实是基于 C++ 和 pthread 线程库的问题,往下深入,也就是操作系统对于线程实现的问题,这篇文章记录了我对操作系统线程技术的认识和理解。


资源下载链接为: https://pan.quark.cn/s/d9ef5828b597 在本文中,我们将探讨如何通过 Vue.js 实现一个带有动画效果的“回到顶部”功能。Vue.js 是一款用于构建用户界面的流行 JavaScript 框架,其组件化和响应式设计让实现这种交互功能变得十分便捷。 首先,我们来分析 HTML 代码。在这个示例中,存在一个 ID 为 back-to-top 的 div 元素,其中包含两个 span 标签,分别显示“回到”和“顶部”文字。该 div 元素绑定了 Vue.js 的 @click 事件处理器 backToTop,用于处理点击事件,同时还绑定了 v-show 指令来控制按钮的显示隐藏。v-cloak 指令的作用是在 Vue 实例渲染完成之前隐藏该元素,避免出现闪烁现象。 CSS 部分(backTop.css)主要负责样式设计。它首先清除了一些默认的边距和填充,对 html 和 body 进行了全屏布局,并设置了相对定位。.back-to-top 类则定义了“回到顶部”按钮的样式,包括其位置、圆角、阴影、填充以及悬停时背景颜色的变化。此外, v-cloak 相关的 CSS 确保在 Vue 实例加载过程中隐藏该元素。每个 .page 类代表一个页面,每个页面的高度设置为 400px,用于模拟多页面的滚动效果。 接下来是 JavaScript 部分(backTop.js)。在这里,我们创建了一个 Vue 实例。实例的 el 属性指定 Vue 将挂载到的 DOM 元素(#back-to-top)。data 对象中包含三个属性:backTopShow 用于控制按钮的显示状态;backTopAllow 用于防止用户快速连续点击;backSeconds 定义了回到顶部所需的时间;showPx 则规定了滚动多少像素后显示“回到顶部”按钮。 在 V
资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 以下是简化后的内容: 程序集变量 计数器:整数型 文本发送计次:整数型 子程序 __启动窗口_创建完毕 _手动发送数据_被单击 停止发送 发送预处理 判断端口是否启动成功,失败则提示并返回 根据组合框选择的进制类型,将编辑框内容转换后发送 发送失败则提示并返回 进制转换(被转换文本,被转换进制,转换的进制) 检查进制范围,错误则返回提示 规范参数,逐字符检查是否符合进制要求,不符合则返回错误提示 若进制相同直接返回原文本 否则进行进制转换并返回结果 _退出_被单击销毁 _组合框_端口号_列表项被选择 停止发送 设置端口号 _组合框_波特率_列表项被选择 停止发送 设置波特率 _组合框_数据位_列表项被选择 停止发送 设置数据位数 _组合框_校验_列表项被选择 停止发送 设置奇偶校验方案 _组合框_停止位_列表项被选择 停止发送 设置停止位数 发送预处理 停止发送 设置波特率、端口号、数据位数、奇偶校验方案、停止位数 根据奇偶校验方案设置校验标志 _选择框_DTR_被单击 根据选中状态设置信号操作 _选择框_RTS_被单击 根据选中状态设置信号操作 _选择框_Break_被单击 根据选中状态设置信号操作 _编辑框_发送周期_内容被改变 若时钟标志选中,设置时钟周期 _选择框_时钟标志_被单击 若选中,设置发送方式为时钟模式,启动发送并设置时钟周期 否则,停止发送,设置时钟周期为0 _组合框_发送方式_列表项被选择 根据选择设置时钟标志和时钟周期 _端口_发送数据_收到信号 _端口_接收数据_收到信号 _端口_接收数据_数据到达 根据接收数据的进制选择,将数据转换后显示在编辑框中 _时钟1_周期事件 根据发送方式和进制选择,周期性发送数据 打开并读入文件 打开文件,读取内容到编辑框 _打开
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值