【Linux】多线程01 --- 理解线程 线程控制及封装

news2024/11/29 9:47:21

🍎作者:阿润菜菜
📖专栏:Linux系统编程


目录

  • 一、线程概念 -- 理解线程与进程的区别和联系
    • 1. 再次理解用户级页表和进程地址空间
    • 2.理解Linux的轻量级进程
    • 3. 线程的属性
    • 4.线程的优点和缺点
    • 二、线程的控制 --- 学学接口使用


一、线程概念 – 理解线程与进程的区别和联系

在Linux中其实没有真正线程的概念,在Linux中线程的概念其实就是进程内部的一个执行流。在宏观层面上理解,线程是执行流这句话放在任何一个OS上都没错,但落实到具体操作系统上,不同的OS多线程实现策略是不一样的,例如Windows底层就有真正的线程实现(所以程序开多了会卡),而Linux的线程只是一种轻量级进程,下面我们落实到Linux系统的多线程实现策略上,来一起学习一下!

1. 再次理解用户级页表和进程地址空间

在我们写出下面这两行代码时,为什么编译器会报错呢?但是只写第一行编译器会报个Warning,可以编译通过,有没有想过?

char *ptr = "hello world!";
*ptr = "Hello";

在语言级别,我们给出的解释是:

  1. 第一行代码能编过的原因是权限缩小,虽然ptr是可读可写的权限,但在指向常量字符串"hello world"(堆区)之后,ptr的权限就变为了只读,所以如果仅仅修改一下权限,g++并不会报错,只是报个warning罢了,
  2. 但当解引用ptr,将ptr指向的内容修改为"H"字符串后,编译器就会报错了,因为我们说ptr的权限是只读,因为常量字符串是不可修改的,你现在进行了ptr指向内容的修改,编译器则一定会报错!

现在我们来看看内核角度,为什么ptr指针指向一修改,编译器就能报错呢?进程就会退出呢?进程怎么知道的?怎么被终止的?
在这里插入图片描述

实际上,页表帮我们做的事情不止虚拟地址到物理地址空间的映射转换这么简单!他还会记录虚拟地址映射到物理地址的权限,如读写及执行权限,用户层/内核层权限,虚拟地址是否有效命中到对应的物理地址上等等!
所以上面解引用指针ptr时,底层经过用户级页表映射,MMU会发现ptr这个虚拟地址对应的权限是R权限,那就是只读不能被修改,此时进程如果执意要进行修改,那就会导致硬件MMU直接报错,操作系统知晓MMU报错后,就会给对应的进程发11号信号(Segmentation fault),当进程在合适的时候就会去处理这个信号,处理信号的默认动作就是终止当前进程!

如何理解用户级页表和进程地址空间呢?-

从功能角度来谈,进程地址空间就是进程能够看到的资源的窗口,因为进程所占用的系统资源都是分配在物理内存上的,想要访问这些系统资源都需要地址空间来作为中间件去访问。
页表真正决定了进程实际拥有资源的情况,进程对某个资源具有什么权限?访问此资源需要的进程级别?一个不属于当前进程的虚拟地址,进程能否通过这个地址访问对应物理内存上的资源呢?这些问题都需要依靠页表来解决!所以进程对资源的真正掌握情况是通过页表来实现的!
那该如何对进程的资源进行划分呢? 合理的对地址空间+页表进行资源划分,我们就可以对进程的所有资源进行分类!

那虚拟地址到底是如何转换到物理地址的?
实际上,OS作为软硬件资源的管理者,实施的还是那套经典方法:“先组织,在管理”。
我们知道Linux中虚拟地址到物理地址的转换是通过MMU(内存管理单元)和页表(page table)来实现的。而页表是OS的一种数据结构,用于存储虚拟地址和物理地址之间的映射关系。Linux使用多级页表,通常有四级:页全局目录(PGD)、页上级目录(PUD)、页中间目录(PMD)和页表(PT)。每一级页表都有一个索引,用于定位下一级页表的地址。最后一级页表中的表项包含了物理地址的基地址,再加上虚拟地址的偏移量,就得到了最终的物理地址。

这个过程可以用以下图来表示:
在这里插入图片描述

具体参考: Linux内核学习3——虚拟地址转换成物理地址

2.理解Linux的轻量级进程

1.我们可以将进程的资源划分给不同的线程,让线程来执行某些代码块儿,而线程就是进程内部的一个执行流。那么此时我们就可以通过地址空间+页表的方式将进程的资源划分给每一个线程,那么线程的执行粒度一定比之前的进程更细!

2.Linux中并没有专门为线程创建真正的数据结构来管理,而是直接复用进程的PCB当作线程的描述结构体,用PCB来当作Linux系统内部的"线程"。 这么做的好处是什么呢?如果要创建真正的线程结构体,那就需要对其进行维护,需要和进程构建好关系,每个线程还需要和地址空间进行关联,CPU调度进程和调度线程还不一样,操作系统要对内核中大量的进程和线程做管理,这样维护的成本太高了!不利于系统的稳定性和健壮性,所以直接复用PCB是一个很好的选择,维护起来的成本很低,因为直接复用原来的数据结构就可以实现线程。所以这也是linux系统既稳定又高效,成为世界上各大互联网公司服务器系统选择的原因

3.所以Linux内核是怎么设计线程的? Linux用进程的PCB来模拟线程,是完全属于自己实现的一套方案!站在CPU的角度来看,每一个PCB,都可以称之为轻量级进程,因为它只需要PCB即可,而进程承担分配的资源更多,量级更重!
Linux线程是CPU调度的基本单位,进程是承担分配系统资源的基本实体!
进程用来整体向操作系统申请资源,线程负责向进程伸手要资源。如果线程向操作系统申请资源,实质上也是进程在向操作系统要资源,因为线程在进程内部运行,是进程内部的一部分!
用pcb模拟线程的好处是维护成本大大降低,系统变得更加可靠、高效、稳定。windows操作系统是给老百姓用的,可用性必须要高。linux是给程序用的,必须要可靠稳定高效。所以由于需求的不同,产生了不同实现方案的操作系统。

我们说Linux中没有线程只有轻量级进程,怎么证明呢?
因为Linux内核并没有单独为线程设计数据结构,而是复用了进程的PCB。所以Linux无法直接提供创建线程的系统调用接口,只能提供创建轻量级进程的接口。轻量级进程是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。

Linux为了让用户能够得到他想要的线程,只能通过原生线程库来给用户他想要的,所以在用户和内核之间有一个软件层,这个软件层负责给程序员创建出程序员想要的线程。除这个原生线程库会创建出线程结构体外,但同时linux内核中会通过一个叫clone的系统调用来对应的创建出一个轻量级进程,所以我们称这个库是用户级线程库,因为linux是没有真正意义上的线程的,无法给用户创建线程,只能创建对应的PCB,也就是轻量级进程!
我们要证明Linux中没有线程只有轻量级进程,可以通过查看 /proc目录下的进程信息,或者使用ps -eLf 命令查看进程和线程的标识符。所以Linux下线程实际上是封装了原生线程库的!
在这里插入图片描述

而且如果在编译时不带-lpthread选项,可以看到g++报错pthread_create()函数未定义,其实就是因为链接器链接不上具体的动态库,此时就可以看出来linux内核中并没有真正意义的线程,他无法提供创建线程的接口,而只能通过第三方库libpthread.so或libpthread.a来提供创建线程的接口。

3. 线程的属性

请简述什么是LWP?
LWP是轻量级进程,在Linux下进程是资源分配的基本单位,线程是cpu调度的基本单位,而线程使用进程pcb描述实现,并且同一个进程中的所有pcb共用同一个虚拟地址空间,因此相较于传统进程更加的轻量化。

我们可以通过ps -aL 命令就可以看到正在运行的线程有哪些,可以看到有两个标识符,一个是PID,一个是LWP(light weight process),所以CPU在调度那么多的PCB时,其实是以LWP作为每个PCB的标识符,以此来区分进程中的多个轻量级进程(线程)。
主线程的PID和LWP是相同的,所以从CPU调度的角度来看,如果进程内只有一个执行流,那么LWP和PID标识符对于CPU来说都是等价的,但当进程内有多个执行流时,CPU是以LWP作为标识符来调度线程,而不是以PID来进行调度。
在这里插入图片描述

线程一旦被创建,几乎所有的资源都是共享的!
因为一个进程中的所有线程都共享进程地址空间,地址空间中的栈,堆,已初始化/未初始化数据段,代码段,这些区域中的资源都是共享的,每个线程都可以看到,那么任意一个线程就都可以去访问这些资源了!
所以如果线程想要通信,那成本是要比进程间通信低很多的,由于进程具有独立性,所以进程间通信的前提是让不同的进程能够看到同一份资源,看到同一份资源的成本就很大,例如之前我们所学的,通过创建管道或共享内存的方式来让进程先能够看到同一份资源,然后才能继续向下谈通信的话题。但是今天,对于线程来说完全不需要考虑看到同一份资源这个问题,因为一个进程内的所有线程天然的可以共享进程地址空间,你可以直接定义一个全局缓冲区,一个线程往里写,另一个线程立马就可以从缓冲区中看到另一个线程写的信息,所以线程通信的成本非常低!
在这里插入图片描述
那什么资源是线程应该私有的呢?

a.线程PCB的属性,例如线程id,线程调度优先级,线程状态等等…(这个回答不回答不重要,重要的是回答出下面那两点)
b.线程在被CPU调度时,也是需要进行切换的,所以,线程的上下文结构也必须是线程的私有资源。(这点可以体现出我们知道线程是动态的,CPU调度线程会轮换,线程会被切换上来也会被切换下去)
c.每个线程都会执行自己的线程函数,就是那个start_routine函数指针所指向的函数,所以每个线程都有自己的私有栈结构。

在这里插入图片描述
Linux中轻量级进程之间可以共享进程的资源和环境,如代码段、数据段、堆、文件描述符、信号处理器、当前工作目录等。但是轻量级进程也有自己的私有数据,如寄存器组、栈空间、错误返回码、信号屏蔽字、优先级等

4.线程的优点和缺点

线程优点:
在这里插入图片描述

缺点:
在这里插入图片描述

在这里插入图片描述

二、线程的控制 — 学学接口使用


未完待续

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

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

相关文章

企业级帮助中心编写方案

随着互联网的飞速发展,越来越多的企业开始将客户服务转向线上服务。在这个过程中,企业级帮助中心因其高效的自助服务和低成本的维护方式受到越来越多企业的青睐。下文将从如何编写一个高质量的企业级帮助中心入手,为您介绍具体步骤。 一、明…

架构愿景: 构建良好软件的关键

在产品开发生命周期的各个阶段,牢记架构愿景,始终坚持每个决策都符合愿景原则,是避免架构腐化的唯一方式。原文: Architecture Vision — A critical ingredient in building well-maintained software 上一篇文章《软件架构: 一切皆有代价》…

华为OD机试真题B卷 Java 实现【字符串通配符】,附详细解题思路

一、题目描述 问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求: 实现如下2个通配符: :匹配0个或以上的字符&#xf…

“国风顶流”霸王茶姬,眺望书画诗酒的远方

一杯来自云南的原叶鲜奶茶,如何征服消费者的胃和心? 茶饮赛道素来竞争激烈,十年时间,行业从鲜奶茶卷到奶盖茶、水果茶、多料奶茶等一个又一个新品类。茶饮品牌如雨后春笋般涌现,甚至不少咖啡品牌都跨界而来&#xff0…

【新星计划回顾】第三篇学习计划-分页和排名函数的运用

🏆🏆今天是【全国科技者工作日】,在这个特别的日子里,自然要写篇文章! 最近这段时间非常忙,虽然导师首次参与新星计划活动已经在4月16日圆满结束,早想腾出时间来好好整理活动期间分享的知识点。…

实战一个react(0-1)项目

文章目录 1. 安装2. 完成一个组件开发3. 添加路由3. 引入element-react1. 运行发现报错./node_modules/element-react/dist/npm/es5/src/locale/format.js2. 接着又报错The <Router /> component appears to be a function component that returns a class instance. Cha…

ABP VNext认证授权获取Token

ABP VNext认证授权获取Token 1.Password授权方式获取1.1 请求说明1.2 请求示例1.3 请求参数 2.authorization_code模式获取2.1 无认证授权&#xff0c;跳转至授权认证中心2.2 用户密码登录2.3 登录成功&#xff0c;服务器会跳转至redirect_url所指地址 1.Password授权方式获取 …

vue-kindeditor 安装和解决问题

效果图 kindeditor 引入 一、去官网下载 kindeditor 包 官方链接 二、在vue里的static文件夹下 创建一个 文件夹名字叫 kindeditor&#xff0c; 把下载好的文件放在这里 三、在 公共组件 components 下 创建kindeditor.vue 文件 <template><div class"kindedit…

拿到字节跳动奖学金,入职字节跳动做科研,他们经历了什么?

前不久&#xff0c;第三届字节跳动奖学金计划已经正式启动。 自 2021 年起&#xff0c;字节跳动奖学金计划已经完成了两届评选&#xff0c;共有 19 位优秀学子荣获每人 10 万元人民币的奖学金。 在奖学金支持下&#xff0c;他们获得了新的科研项目费用、学术交流机会&#xff0…

高压放大器在驱动压电陶瓷进行铝板无损检测中的应用研究

想要达成在不损害或不影响被测对象使用性能及自身性质的前提下&#xff0c;对被测对象内部进行缺陷&#xff0c;结构&#xff0c;失效分析&#xff0c;就得用到无损检测&#xff08;Non Destructive Testing&#xff09;技术&#xff0c;最常用的无损检测方法有很多&#xff0c…

【网络安全知识】网络技术领域术语大全,强烈建议收藏!

自主访问控(DAC:Discretionary Access Control) 自主访问控制(DAC)是一个访问控制服务&#xff0c;其执行一个基于系统实体身份的安全政策和它们的授权来访问系统资源。 双附接集线器(DAC: Dual-attached Concentrator) 双附接集线器(DAC)是FDDI或CDDI集线器有能力接入到一个…

RK3568 AP6275S蓝牙驱动程序调度过程

1、前言 今年3月份调度了RK3568驱动程序&#xff0c;当时由于时间的问题&#xff0c;AP6275S蓝牙驱动程序没有调试成功。当时仔细检查的设备树的配置。 wireless_bluetooth: wireless-bluetooth {compatible "bluetooth-platdata";clocks <&rk809 1>;cl…

离散数学_十章-图 ( 4 ):图的表示和图的同构

&#x1f4f7;10.4 图的表示和图的同构 1. 图的表示1.1 邻接表1.1.1 简单图的邻接表1.1.2 有向图的邻接表 1.2 邻接矩阵❗在邻接表和邻接矩阵之间取舍1.3 关联矩阵 2. 图同构3. ⚡判断两个简单图是否同构 图的表示方式有很多种&#xff0c;选择最方便的表示有助于对图的处理~ …

Navicat 面向 PostgreSQL 查询超时的工具解决方案

文章目录 Navicat 面向 PostgreSQL 查询超时的工具解决方案查询超时的必要性应用场景 查询分析器 | Navicat Monitor在数据库级别设置为特定用户设置查询超时 结语 Navicat 面向 PostgreSQL 查询超时的工具解决方案 早前&#xff0c;我们发表过一篇《PostgreSQL 与 Navicat &am…

Datax ftp写入hive

这是一个巨大的坑&#xff0c;网上对这块的完整描述真的很少&#xff0c;新手真的会很迷茫&#xff01;&#xff01;&#xff01; 插件 选择插件 reader插件选择&#xff1a;ftpread write插件选择&#xff1a;hdfswrite 参数配置 reader参数 "parameter": {/…

干货|SpringCloud全家桶微服务初探

SpringCloud的从整体架构上看&#xff0c;相对来说是完整的、庞大的。它不仅仅是一个基础性架构工具&#xff0c;它为微服务架构提供了一个“全家桶”的套餐。每一个模块关注各自的职能&#xff0c;并且能够很好地配合与协作&#xff0c;能够帮助入门者快速搭建起一套微服务架构…

前后端联调跨域问题

文章目录 什么是同源策略如何判断是否同源&#xff1f;跨域资源共享(CORS)如何解决跨域问题 什么是同源策略 同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。 如何判断是否同源&#xff1f; 如果…

从中国人民大学与加拿大女王大学金融硕士的学员构成,了解金融行业都有哪些职位

金融行业最受欢迎的岗位莫过于券商、银行、基金公司、私募市场、体制内&#xff08;监管部门、交易所等&#xff09;、信托、大企业投资部、保险、管理咨询、资产管理。在当下如果要选择工作&#xff0c;想找就业率第一、薪酬排名第一的行业&#xff0c;那一定是金融工作。中国…

03 redis新类型bitmap/hyperloglgo/GEO

亿级系统中常见的四种统计 聚合统计 统计多个集合元素的聚合结果&#xff0c;就是前面讲解过的交差并等集合统计交并差集和聚合函数的应用 排序统计 抖音视频最新评论留言的场景&#xff0c;请你设计一个展现列表。考察你的数据结构和设计思路设计案例和回答思路以抖音vcr最…

3.java高级之GUI编程

1.gui (graphical user interface) awt sun公司最早的gui,不美观,不兼容各平台swing : awt升级2.顶层容器(只有一个)(其他的只能放这里)Jframe Jdialog对话框 Jwindow(x) //在main方法写fnew Jframe(); f.setSize(300,300); //设置大小f.setTitle("hello"); //设置…