操作系统 2.3-用户级线程
多进程的回顾

-
多进程概念:
-
操作系统能够同时管理多个进程(PID:1, PID:2, PID:3),每个进程可以独立执行一系列指令。
-
-
进程结构:
-
每个进程拥有自己的代码段、数据段、堆和栈。
-
进程控制块(PCB)记录了进程的状态和上下文,如程序计数器(PC)、寄存器值(如ax, bx)等。
-
-
内存管理:
-
进程通过映射表管理虚拟地址到物理地址的转换,确保进程间的内存隔离。
-
-
进程状态:
-
进程可以处于不同的状态,如运行态、阻塞态(如等待磁盘I/O操作完成)。
-
-
进程切换:
-
操作系统负责在不同进程间进行切换,以实现多任务并发执行。
-
-
进程通信和同步:
-
进程间需要通信和同步机制来协调工作,如共享数据时需要同步。
-
-
操作系统的角色:
-
操作系统负责管理所有进程,包括进程的创建、调度、切换和终止。
-
线程的概念

进程和线程切换的原理及区别总结如下
-
进程的组织:
-
进程通过状态(如新建、就绪、运行、阻塞、终止)和队列(如就绪队列、阻塞队列)进行组织。
-
-
进程切换:
-
进程切换涉及保存当前进程状态(上下文),选择下一个进程,并恢复其状态,实现进程间的切换。
-
-
线程的概念:
-
线程是进程内的轻量级执行单元,共享进程的资源,如内存空间和文件描述符。
-
用户级线程在用户态执行,不涉及内核态资源切换,因此切换代价较小。
-
-
线程切换的优势:
-
线程切换速度快,因为不需要切换内存地址空间,只需切换指令执行序列(即程序计数器PC)。
-
线程适合实现并发执行,提高系统资源利用率和响应速度。
-
-
进程与线程的区别:
-
进程是资源分配的基本单位,拥有独立的内存空间。
-
线程共享进程的资源,但可独立调度和执行。
-
进程切换涉及资源和状态的全面切换,而线程切换通常只涉及执行状态的切换。
-
-
用户级线程:
-
用户级线程完全在用户态运行,由用户程序控制,不涉及内核态资源管理。
-
用户级线程的创建、调度和销毁不需要内核干预,由线程库管理。
-
总结
进程和线程是操作系统实现多任务处理的两种机制。进程提供资源隔离,而线程提供轻量级的并发执行。线程切换比进程切换更高效,因为线程切换不需要切换内存地址空间
多线程的实用性

-
多执行序列的实用性:
-
多个执行序列(线程)可以在单个地址空间(进程)内有效运行。
-
这种模型在现代操作系统中非常实用,特别是在图形用户界面(GUI)应用程序中。
-
-
网页浏览器中的线程使用:
-
一个线程用于从服务器接收数据。
-
一个线程用于显示文本内容。
-
一个线程用于处理图片(例如解压缩)。
-
一个线程用于显示图片。
-
-
线程资源共享:
-
线程之间需要共享某些资源,例如从服务器接收的数据需要在不同线程间传递,以便正确显示网页内容。
-
尽管每个线程执行不同的任务,但它们可能需要访问相同的数据或资源。
-
-
资源管理和同步:
-
操作系统需要管理这些线程如何共享资源,例如通过互斥锁、信号量等同步机制来防止数据竞争条件和保证数据一致性。
-
线程间正确的同步是实现高效多线程应用程序的关键。
-
-
用户界面的一致性:
-
所有的文本和图片最终都显示在同一个屏幕上,要求线程协作无间断地更新用户界面。
-
综上所述,多个执行序列加上单个地址空间的模型不仅实用,而且是现代操作系统中实现多任务并行和资源有效管理的基础。线程作为轻量级的执行单元,能够提高程序的响应性和执行效率,但也需要仔细的资源管理和同步控制来确保程序的正确性和稳定性。
多线程的具体实现
总览

上面网页的代码示例
void WebExplorer()
{char URL[] = "http://cms.hit.edu.cn";char buffer[1000];pthread_create(..., GetData, URL, buffer);pthread_create(..., Show, buffer);
}
void GetData(char *URL, char *p) { ... }
void Show(char *p) { ... }
-
WebExplorer函数是浏览器的主函数,它定义了一个URL字符串和一个缓冲区buffer,用于存储从URL下载的数据。 -
使用
pthread_create函数创建了两个线程,一个用于下载数据(GetData函数),另一个用于显示数据(Show函数)。 -
GetData函数负责从指定的URL下载数据,并将其存储在buffer中。 -
Show函数负责将buffer中的数据展示出来。
执行流程图
执行流程图展示了这两个线程的执行流程和交互:
-
GetData线程在10:05开始连接并下载文本数据,假设在10:07下载完成。 -
下载完成后,
GetData线程通过yield操作主动让出CPU,使得Show线程有机会执行。 -
Show线程在10:00开始执行,负责显示文本数据。 -
在显示文本数据后,
Show线程也通过yield操作让出CPU,使得GetData线程可以继续执行下载图片的操作。
解释说明
-
pthread_create函数用于创建线程,其参数包括线程属性、线程函数和传递给线程函数的参数。 -
yield操作是线程主动让出CPU的行为,允许其他线程有机会执行。这在用户级线程中非常常见,用于实现线程间的协作和调度。、
那么我们接下来来探讨这两个函数到底要怎么实现
Yield的简单实现
主要讲解了在操作系统中如何通过编程实现线程切换,以及yield函数在线程切换中的作用。下面我将结合这些图和文字,详细解释yield函数是如何一步一步实现的。

图1:Create和Yield的核心概念
-
核心是Yield:
yield函数是实现线程切换的核心。通过yield,一个线程可以主动放弃CPU的使用权,让其他线程有机会执行。 -
Create的作用:
create函数用于创建新的线程,它需要制造出第一次切换时应该的样子,即设置好线程的初始状态,包括程序计数器(PC)和栈指针(ESP)。

图2:两个执行序列与一个栈
-
问题描述:图中展示了两个函数
A()和C(),每个函数中都有一个yield调用。问题是,由于两个函数共用一个栈,当一个函数执行yield时,会将返回地址压入栈中。但是,如果直接从栈中弹出返回地址继续执行,可能会导致执行流程错误地跳转到另一个函数中。因此,需要一种机制来正确地管理这些返回地址,确保每个函数在自己的栈中正确执行。

图3:从一个栈到两个栈
-
引入TCB:为了解决图2中的问题,引入了线程控制块(TCB)的概念。每个线程都有自己的TCB和栈,这样在执行
yield时,可以保存当前线程的栈指针到TCB中,并从另一个线程的TCB中恢复栈指针,从而实现正确的线程切换。 -
Yield的实现:
yield函数首先保存当前线程的栈指针到其TCB中,然后从另一个线程的TCB中恢复栈指针,最后通过跳转到保存的返回地址来继续执行。这样,每个线程都可以在自己的栈中独立执行,而不会干扰到其他线程。
代码说明
yield 函数的代码实现
void Yield()
{TCB1.esp = esp; // 保存当前线程的栈指针到其TCB中esp = TCB2.esp; // 从下一个线程的TCB中恢复栈指针// jmp 204; // 应该去掉,因为返回地址已经在栈中
}
-
保存当前线程的栈指针:
-
TCB1.esp = esp;这行代码将当前线程的栈指针(ESP)保存到当前线程的TCB中。这是为了在后续切换回当前线程时能够恢复其栈状态。
-
-
切换到下一个线程的栈指针:
-
esp = TCB2.esp;这行代码将ESP寄存器的值更新为下一个线程的栈指针,从而实现栈的切换。
-
yield 函数的作用
yield 函数在多线程环境中用于实现线程间的协作式切换。具体作用包括:
-
线程切换:允许当前线程主动放弃CPU控制权,使调度器有机会调度其他线程执行。
-
栈切换:通过保存和恢复栈指针,实现线程间栈空间的切换。
-
程序计数器(PC)切换:虽然代码中没有直接修改PC,但通过栈管理,确保了线程切换后能从正确的地址继续执行。
Create的简单实现

图示说明
-
图示:展示了内存布局,包括两个栈(Stack1和Stack2)、堆(Heap)、数据段和代码段。
-
栈:每个线程有自己的栈,用于存储函数调用的返回地址和其他局部变量。
-
TCB:每个线程有自己的TCB,用于存储线程的状态信息,包括栈指针(ESP)。
ThreadCreate函数的实现
-
函数定义:
void ThreadCreate(A) -
步骤:
-
分配TCB:使用
malloc分配内存用于存储TCB。 -
分配栈:使用
malloc分配内存用于线程的栈。 -
设置栈指针:将栈的起始地址赋值给TCB中的ESP字段。这里假设栈从高地址向低地址增长,所以栈指针指向栈的起始地址。
-
设置初始执行地址:将线程的起始函数地址(如
A函数的地址)放入栈中,这样当线程开始执行时,它将从指定的函数开始执行。
-
代码示例
void ThreadCreate(void (*func)()) {TCB *tcb = malloc(sizeof(TCB)); // 分配TCBvoid *stack = malloc(STACK_SIZE); // 分配栈空间*stack = (void *)func; // 将函数地址放入栈中tcb->esp = stack; // 设置栈指针// 启动线程执行
}
总结
通过ThreadCreate函数,操作系统可以在用户态下创建新的线程,每个线程有自己的TCB和栈。这种用户级线程的实现方式不需要内核支持,可以提高程序的并发性和响应性。
create和yield结合

1. WebExplorer 函数
void WebExplorer() // main()
{ThreadCreate(GetData, URL, buffer);while(1) Yield();
}
用途:
-
这是主函数,用于初始化并启动多线程Web浏览器。
-
调用
ThreadCreate来创建一个新线程,该线程执行GetData函数以下载数据。 -
进入一个无限循环,在每次迭代中调用
Yield函数,以允许其他线程运行。
2. GetData 函数
void GetData(char *URL, char *p)
{连接URL; 下载; Yield();...
}
用途:
-
负责从指定的 URL 下载数据。
-
执行下载操作后,调用
Yield函数以让出CPU,允许其他线程(如显示线程)运行。
3. ThreadCreate 函数
void ThreadCreate(func, arg1)
{申请栈; 申请TCB; func等入栈; 关联TCB与栈;...
}
用途:
-
创建一个新的线程。
-
为新线程分配栈和TCB(线程控制块)。
-
将线程的起始函数地址压入栈中。
-
关联TCB和栈,以便线程可以正确地开始执行。
4. Yield 函数
void Yield()
{压入现场; esp放在当前TCB中; Next(); 从下个TCB取出esp; 弹栈切换线程;
}
用途:
-
实现线程切换。
-
保存当前线程的状态(将ESP压入栈中),并从下一个线程的TCB中恢复栈指针(ESP),从而切换到下一个线程。
-
通过这种方式,允许多个线程交替执行,实现多任务并发处理。
这些代码片段展示了如何在用户态下实现简单的多线程并发模型,包括线程的创建、执行和切换。
相关文章:
操作系统 2.3-用户级线程
多进程的回顾 多进程概念: 操作系统能够同时管理多个进程(PID:1, PID:2, PID:3),每个进程可以独立执行一系列指令。 进程结构: 每个进程拥有自己的代码段、数据段、堆和栈。 进程控制块(PCB)…...
解决火绒启动时,报安全服务异常,无法保障计算机安全
1.找到控制面板-安全和维护-更改用户账户控制设置 重启启动电脑解决。...
2025-03-07 :详细介绍一下 Databricks 的 Lakehouse
Databricks 的 Lakehouse 是一种结合了数据湖和数据仓库优势的现代数据架构。它旨在解决传统数据湖和数据仓库的局限性,提供高效、灵活且可扩展的数据管理解决方案。以下是关于 Databricks Lakehouse 的详细介绍: 1. Lakehouse 的概念 Lakehouse 是一种…...
小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡
在微信小程序中,事件分为 冒泡事件 和 非冒泡事件 : 冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递;(如果父节点中也绑定了一个事件,父节点事件也会被触发,也就是说子组…...
STM32点亮LED灯
1.1 介绍: LED模块。它的控制方法非常简单,要想点亮LED,只要让它两端有一定的电压就可以;实验中,我们通过编程控制信号端S的高低电平,从而控制LED的亮灭。我们提供一个测试代码控制LED模块上实现闪烁的效果…...
C++ primer plus 第七节 函数探幽完结版
系列文章目录 C primer plus 第一节 步入C-CSDN博客 C primer plus 第二节 hello world刨析-CSDN博客 C primer plus 第三节 数据处理-CSDN博客 C primer plus 第四节 复合类型-CSDN博客 C primer plus 第五节 循环-CSDN博客 C primier plus 第七节 函数探幽第一部分-CSDN博客 …...
共聚焦显微镜的使用操作流程
一、使用前准备: 在使用显微镜进行细胞制片观察之前,一系列细致的准备工作是必不可少的。首先,将废液缸从框架内取出,清空并清洗,确保无残留液体干扰后续实验。接着,倒取适量的PBS(磷酸盐缓冲液…...
打破界限!家电行业3D数字化营销,线上线下无缝对接
家电行业正步入从增量市场向存量市场的转型期,消费者的观念日益成熟,对产品体验和服务质量的要求愈发严格。无论是线上电商平台还是线下实体店铺,提供个性化、增强体验感的产品与服务已成为家电市场未来发展的核心动力。51建模网凭借“3D数字…...
13 【HarmonyOS NEXT】 仿uv-ui组件开发之Avatar组件进阶指南(四)
温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦! 文章目录 补充内容第四篇:打造高性能Avatar组件的终极优化秘籍1. 性能优化策略1.1 状态管理优化1.2 渲染性能优化 2. 资源优化2.1 图片…...
[Vue warn]: Duplicate keys detected: ‘xxx‘. This may cause an update error.
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》 🍚 蓝桥云课签约作者、…...
设计模式 - 工厂模式 精准梳理精准记忆
1、代码片段 - 带入理解 一、核心模式分类 简单工厂模式(编程习惯,非 GoF 设计模式)工厂方法模式(GoF 创建型模式)抽象工厂模式(GoF 创建型模式) 二、演变过程:咖啡店案例 初始实现…...
NVIDIA(英伟达) GPU 芯片架构发展史
GPU 性能的关键参数 CUDA 核心数量(个):决定了 GPU 并行处理能力,在 AI 等并行计算类业务下,CUDA 核心越多性能越好。 显存容量(GB):决定了 GPU 加载数据量的大小,在 AI…...
springboot项目使用中创InforSuiteAS替换tomcat
springboot项目使用中创InforSuiteAS替换tomcat 学习地址一、部署InforSuiteAS1、部署2、运行 二、springboot项目打包成war包 特殊处理1、pom文件处理1、排除内嵌的tomcat包2、新增tomcat、javax.servlet-api3、打包格式设置为war4、打包后的项目名称5、启动类修改1、原来的不…...
八、Redis 过期策略与淘汰机制:深入解析与优化实践
Redis 过期策略与淘汰机制:深入解析与优化实践 Redis 作为基于内存的高性能数据库,如何管理过期的键(key)和当内存不足时如何淘汰数据,是影响 Redis 性能和稳定性的关键因素。本篇文章将深入解析 Redis 的过期 key 处理方式和数据淘汰策略,并结合实际应用场景,帮助开发…...
Tomcat-web服务器介绍以及安装部署
一、Tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用…...
C#释放内存空间的方法
目录 前言释放 C# 对象内存的六种方法1、手动释放内存空间2、使用 Using 语句3、使用 垃圾回收器4、GC.Collect() 方法5、GC.WaitForPendingFinalizers() 方法6、WeakReference 类 注意 前言 当不再需要对象时释放内存空间对于防止内存泄漏和提高应用程序性能至关重要。C# 提供…...
18类创新平台培育入库!长沙经开区2025年各类科技创新平台培育申报流程时间材料及申报条件
长沙经开区打算申报企业研发中心、技术创新中心、工程技术研究中心、新型研发机构、重点实验室、概念验证中心和中试平台、工程研究中心、企业技术中心、制造业创新中心、工业设计中心等创新平台的可先备案培育入库,2025年各类平台的认定将从培育库中优先推荐&#…...
使用 Elasticsearch 进行集成测试初始化数据时的注意事项
作者:来自 Elastic piotrprz 在创建应该使用 Elasticsearch 进行搜索、数据聚合或 BM25/vector/search 的软件时,创建至少少量的集成测试至关重要。虽然 “模拟索引” 看起来很诱人,因为测试甚至可以在几分之一秒内运行,但它们实际…...
PostgreSQL常用系统表
1.概念 * 系统表记录了数据库的各种信息,并由SQL命令关联的系统操作表操作会自动维护其中的内容。 * pg_catalog是postgres的系统表命名空间,用于存储系统函数和系统元数据,包含了所有的内置数据类型、函数、表、系统视图等。pg_catalog并不…...
9. Flink的性能优化
1. Flink的资源和代码优化 1.1 slot资源配置 Flink中具体跑任务的进程叫TaskManager,TM进程又会根据配置划分出诺干个TaskSlot,它是具体运行SubTask的地方。slot是Flink用来隔离各个subtask的资源集合,这里的资源一把指内存,TCP…...
【文生图】windows 部署stable-diffusion-webui
windows 部署stable-diffusion-webui AUTOMATIC1111 stable-diffusion-webui Detailed feature showcase with images: 带图片的详细功能展示: Original txt2img and img2img modes 原始的 txt2img 和 img2img 模式 One click install and run script (but you still must i…...
华为:Wireshark的OSPF抓包分析过程
一、OSPF 的5包7状态 5个数据包 1.Hello:发现、建立邻居(邻接)关系、维持、周期保活;存在全网唯一的RID,使用IP地址表示 2.DBD:本地的数据库的目录(摘要),LSDB的目录&…...
视频输入设备-V4L2的开发流程简述
一、摄像头的工作原理与应用 基本概念 V4L2的全称是Video For Linux Two,其实指的是V4L的升级版,是linux系统关于视频设备的内核驱动,同时V4L2也包含Linux系统下关于视频以及音频采集的接口,只需要配合对应的视频采集设备就可以实…...
python基础课程整理--元组的基础
好的,下面详细列举Python元组的特点,包括取值、增加、修改和删除操作: 元组(Tuple) 元组(Tuple)的特点如下: 定义:使用圆括号 () 包裹,可以存储多个元素。…...
Windows设置目录及子目录大小写不敏感暨git克隆报错同名文件已存在的解决办法
在Windows系统中设置目录及其子目录为大小写不敏感,可以通过以下步骤完成: 步骤说明: 以管理员身份运行命令提示符或PowerShell 右键点击“开始”菜单,选择“命令提示符(管理员)”或“Windows PowerShell&…...
浅论数据库聚合:合理使用LambdaQueryWrapper和XML
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、数据库聚合替代内存计算(关键优化)二、批量处理优化四、区域特殊处理解耦五、防御性编程增强 前言 技术认知点:使用 XM…...
CentOS 7.9 安装 ClickHouse 文档
1. 环境准备 确保系统为 CentOS 7.9,并已安装 Docker。如果未安装 Docker,请先安装 Docker。 安装 Docker # 卸载旧版本 Docker(如果有) sudo yum remove -y docker docker-client docker-client-latest docker-common docker-…...
WPS条件格式:B列的值大于800,并且E列的值大于B列乘以0.4时,这一行的背景标红
一、选择数据区域 选中需要应用条件格式的区域(例如A2:E100 )。 二、打开条件格式 点击“开始”选项卡,选择“条件格式” > “新建规则”。 三、选择规则类型 选择“使用公式确定要设置格式的单元格”。 四、输入公式 在公式框中输入以…...
SQL分几种
SQL(Structured Query Language)是用于管理关系型数据库的标准语言。根据功能,SQL 语句可以分为以下几类: 1. 数据查询语言(DQL,Data Query Language) 用于从数据库中查询数据。 核心语句&…...
MWC 2025 | 紫光展锐联合移远通信推出全面支持R16特性的5G模组RG620UA-EU
2025年世界移动通信大会(MWC 2025)期间,紫光展锐联合移远通信,正式发布了全面支持5G R16特性的模组RG620UA-EU,以强大的灵活性和便捷性赋能产业。 展锐芯加持,关键性能优异 RG620UA-EU模组基于紫光展锐V62…...
