操作系统 2.3-用户级线程

news2025/3/13 19:34:52

多进程的回顾

  1. 多进程概念

    • 操作系统能够同时管理多个进程(PID:1, PID:2, PID:3),每个进程可以独立执行一系列指令。

  2. 进程结构

    • 每个进程拥有自己的代码段、数据段、堆和栈。

    • 进程控制块(PCB)记录了进程的状态和上下文,如程序计数器(PC)、寄存器值(如ax, bx)等。

  3. 内存管理

    • 进程通过映射表管理虚拟地址到物理地址的转换,确保进程间的内存隔离。

  4. 进程状态

    • 进程可以处于不同的状态,如运行态、阻塞态(如等待磁盘I/O操作完成)。

  5. 进程切换

    • 操作系统负责在不同进程间进行切换,以实现多任务并发执行。

  6. 进程通信和同步

    • 进程间需要通信和同步机制来协调工作,如共享数据时需要同步。

  7. 操作系统的角色

    • 操作系统负责管理所有进程,包括进程的创建、调度、切换和终止。

线程的概念

进程和线程切换的原理及区别总结如下

  1. 进程的组织

    • 进程通过状态(如新建、就绪、运行、阻塞、终止)和队列(如就绪队列、阻塞队列)进行组织。

  2. 进程切换

    • 进程切换涉及保存当前进程状态(上下文),选择下一个进程,并恢复其状态,实现进程间的切换。

  3. 线程的概念

    • 线程是进程内的轻量级执行单元,共享进程的资源,如内存空间和文件描述符。

    • 用户级线程在用户态执行,不涉及内核态资源切换,因此切换代价较小。

  4. 线程切换的优势

    • 线程切换速度快,因为不需要切换内存地址空间,只需切换指令执行序列(即程序计数器PC)。

    • 线程适合实现并发执行,提高系统资源利用率和响应速度。

  5. 进程与线程的区别

    • 进程是资源分配的基本单位,拥有独立的内存空间。

    • 线程共享进程的资源,但可独立调度和执行。

    • 进程切换涉及资源和状态的全面切换,而线程切换通常只涉及执行状态的切换。

  6. 用户级线程

    • 用户级线程完全在用户态运行,由用户程序控制,不涉及内核态资源管理。

    • 用户级线程的创建、调度和销毁不需要内核干预,由线程库管理。

总结

进程和线程是操作系统实现多任务处理的两种机制。进程提供资源隔离,而线程提供轻量级的并发执行。线程切换比进程切换更高效,因为线程切换不需要切换内存地址空间

多线程的实用性

  1. 多执行序列的实用性

    • 多个执行序列(线程)可以在单个地址空间(进程)内有效运行。

    • 这种模型在现代操作系统中非常实用,特别是在图形用户界面(GUI)应用程序中。

  2. 网页浏览器中的线程使用

    • 一个线程用于从服务器接收数据。

    • 一个线程用于显示文本内容。

    • 一个线程用于处理图片(例如解压缩)。

    • 一个线程用于显示图片。

  3. 线程资源共享

    • 线程之间需要共享某些资源,例如从服务器接收的数据需要在不同线程间传递,以便正确显示网页内容。

    • 尽管每个线程执行不同的任务,但它们可能需要访问相同的数据或资源。

  4. 资源管理和同步

    • 操作系统需要管理这些线程如何共享资源,例如通过互斥锁、信号量等同步机制来防止数据竞争条件和保证数据一致性。

    • 线程间正确的同步是实现高效多线程应用程序的关键。

  5. 用户界面的一致性

    • 所有的文本和图片最终都显示在同一个屏幕上,要求线程协作无间断地更新用户界面。

综上所述,多个执行序列加上单个地址空间的模型不仅实用,而且是现代操作系统中实现多任务并行和资源有效管理的基础。线程作为轻量级的执行单元,能够提高程序的响应性和执行效率,但也需要仔细的资源管理和同步控制来确保程序的正确性和稳定性。

多线程的具体实现

总览

上面网页的代码示例

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; // 应该去掉,因为返回地址已经在栈中
}

  1. 保存当前线程的栈指针

    • TCB1.esp = esp; 这行代码将当前线程的栈指针(ESP)保存到当前线程的TCB中。这是为了在后续切换回当前线程时能够恢复其栈状态。

  2. 切换到下一个线程的栈指针

    • esp = TCB2.esp; 这行代码将ESP寄存器的值更新为下一个线程的栈指针,从而实现栈的切换。

yield 函数的作用

yield 函数在多线程环境中用于实现线程间的协作式切换。具体作用包括:

  • 线程切换:允许当前线程主动放弃CPU控制权,使调度器有机会调度其他线程执行。

  • 栈切换:通过保存和恢复栈指针,实现线程间栈空间的切换。

  • 程序计数器(PC)切换:虽然代码中没有直接修改PC,但通过栈管理,确保了线程切换后能从正确的地址继续执行。

Create的简单实现

图示说明

  • 图示:展示了内存布局,包括两个栈(Stack1和Stack2)、堆(Heap)、数据段和代码段。

  • :每个线程有自己的栈,用于存储函数调用的返回地址和其他局部变量。

  • TCB:每个线程有自己的TCB,用于存储线程的状态信息,包括栈指针(ESP)。

ThreadCreate函数的实现

  • 函数定义void ThreadCreate(A)

  • 步骤

    1. 分配TCB:使用malloc分配内存用于存储TCB。

    2. 分配栈:使用malloc分配内存用于线程的栈。

    3. 设置栈指针:将栈的起始地址赋值给TCB中的ESP字段。这里假设栈从高地址向低地址增长,所以栈指针指向栈的起始地址。

    4. 设置初始执行地址:将线程的起始函数地址(如A函数的地址)放入栈中,这样当线程开始执行时,它将从指定的函数开始执行。

代码示例

void ThreadCreate(void (*func)()) {
    TCB *tcb = malloc(sizeof(TCB));  // 分配TCB
    void *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),从而切换到下一个线程。

  • 通过这种方式,允许多个线程交替执行,实现多任务并发处理。

这些代码片段展示了如何在用户态下实现简单的多线程并发模型,包括线程的创建、执行和切换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2311440.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决火绒启动时,报安全服务异常,无法保障计算机安全

1.找到控制面板-安全和维护-更改用户账户控制设置 重启启动电脑解决。

小程序事件系统 —— 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博客 …

打破界限!家电行业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、原来的不…

Tomcat-web服务器介绍以及安装部署

一、Tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用…

18类创新平台培育入库!长沙经开区2025年各类科技创新平台培育申报流程时间材料及申报条件

长沙经开区打算申报企业研发中心、技术创新中心、工程技术研究中心、新型研发机构、重点实验室、概念验证中心和中试平台、工程研究中心、企业技术中心、制造业创新中心、工业设计中心等创新平台的可先备案培育入库,2025年各类平台的认定将从培育库中优先推荐&#…

使用 Elasticsearch 进行集成测试初始化​​数据时的注意事项

作者:来自 Elastic piotrprz 在创建应该使用 Elasticsearch 进行搜索、数据聚合或 BM25/vector/search 的软件时,创建至少少量的集成测试至关重要。虽然 “模拟索引” 看起来很诱人,因为测试甚至可以在几分之一秒内运行,但它们实际…

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系统下关于视频以及音频采集的接口,只需要配合对应的视频采集设备就可以实…

浅论数据库聚合:合理使用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 )。 二、打开条件格式 点击“开始”选项卡,选择“条件格式” > “新建规则”。 三、选择规则类型 选择“使用公式确定要设置格式的单元格”。 四、输入公式 在公式框中输入以…