Linux系统编程——线程基本概念
目录
一,关于多线程
二,重新理解进程
三,线程VS进程
四,线程周边概念
4.1 线程的数据共享
4.2 线程的优点
4.3 线程的缺点
4.4 线程异常
4.5 线程用途
五,一些问题解答
如何理解将资源分配给各个线程?
既然线程优点这么多,那么是不是线程越多越好?
如何理解我们曾经学的进程呢?
一,关于多线程
概念很多,建议耐心看完哦:
- 进程申请资源都是在地址空间上申请,可以说地址空间是进程的资源窗口。父进程创建子进程,子进程创建出来后就是两个独立的进程了,虽然子进程很多数据都是从父进程来,但是有写时拷贝,所以它们都有自己的独立的地址空间和页表,它们映射到物理内存的位置不同
- 关于线程,比较官方的说法是:线程在进程内部运行,是OS调度的最基本单位
- 我们曾经创建子进程,要创建task_struct(PCB),mm_struct(地址空间数据结构)和相应的页表建立映射,但是今天我们不这么做了,我们创建“子进程”时,只创建task_struct(PCB),不创建任何其它的地址空间和页表,所以也不会在物理内存中开辟空间给这个“子进程”,与父进程“共用同一个资源窗口”
- 然后我们多创建一些这样“只创建PCB”的子进程,然后“先描述,再组织”,将当前主进程的地址空间(资源)以一定方式划分给不同的task_struct,然后每个进程都分发一些任务让它们做,这样每个“子进程”都可以malloc申请空间,共享区共享,每个线程使用栈区的一部分,就可以让所有的“子进程”的资源都在一个地址空间里申请和运行(简单来说就是所有新创建的进程与父进程共享一个地址空间)
- 而对于CPU,它不受影响,因为CPU的等待队列里只有PCB,CPU只认PCB,所以上面的没有独立地址空间和页表的“子进程”在CPU看来是一样的
- 这样产创建进程的方式和我们以前创建进程的方式有很大不同的是,我们不再创建地址空间和页表了,只创建PCB,然后线程直接伸手向父进程要资源就可以了 --> 我们把每一个这样的子进程的PCB称之为线程,线程可以让每个线程对应地函数由一个一个顺序执行编程并发执行
下面用图来解释:
我们曾经学的进程是下面这样的:

有了线程概念后,这个图会变成这样:
那么在Linux看来:
1,线程是在地址空间中运行的
2,每一个线程执行进程代码的一部分,所以线程的执行粒度比进程要轻很多
问题:为什么说线程在进程的地址空间中运行呢?
解答: 任何执行流要运作,必须要有资源。目前我们可以把这个“资源”简单理解为“代码”,你要想运行一个进程,那么首先得写代码,对吧
二,重新理解进程
有了线程的概念,再加上我们前面的进程的知识,下面用红色框框框起来的部分,这个整体我们叫做“轻量级进程”,如下图:

- 所以前面说的“线程在进程内运行”,我们理解为线程在进程的地址空间中运行,而对于“是OS调度的基本单位”,我们可以理解为CPU只有调度执行流的概念,也就是CPU不关心执行流是线程还是进程,只关心PCB(这是Linux系统特有的实现线程的方案),这点和Tcp协议“面向字节流”的概念很类似
- 许多教材说的线程的概念:线程比进程的执行力度更细,所需资源更少,调度轻量化成本更低。这只是线程的优点,因为不同的OS对于线程有着不同的实现方案,只要满足教材里说的,都是线程
- 所以Linux与其它OS相比,Linux没有为线程专门设计数据结构,(Windows有),线程在概念上和进程是高度重合的,OS中有大量进程那么也就会有大量线程,这就代表线程也要和进程一样“先描述,再组织”,所以OS不得不创建线程的数据结构来管理线程
- 但是,如果线程也要创建数据结构,那么实现起来会非常非常非常复杂,struct_tcb; thread_ctrl_block。但是Windows就这么干了,所以我们很佩服也很同情开发Windows的程序员们,因为太复杂了
- 但是Linux系统设计者没有这么做,Linux设计者用前面我们说的,直接用PCB代替线程的结构体巧妙地实现了线程地功能,也就是“用PCB模拟线程”,最简单直接地体现就是:服务器绝大多数都是Linux操作系统,所以Linux系统一开机一年甚至几年都可以不关机,Windows不敢。
三,线程VS进程
进程是承担分配系统资源的基本实体,线程是调度的基本单位
前面说过,线程在进程内部运行,是操作系统调度的基本单位,后面又补充道,线程其实是在进程的地址空间上运行,并且线程和进程在CPU看来都是一样的,线程的执行力度比进程轻,因为线程都是执行进程代码的一部分,就好比,一个人干的工作好几个人一起干了,肯定轻松很多
问题:为什么线程切换的成本更低呢?
- 首先线程切换不同于进程切换,地址空间不需要切换,而且页表也不需要切换
- CPU内部是有L1-L3 cache缓存的,CPU读取指令时,会把指令放到cache里,下次再来时有大概念就不会再来一个加载一个来一个加载一个了,那样整机效率会变低,放到cache里的话,下次就不需要再从汇编语言加载到CPU里了,直接在CPU内部自己执行,提升效率(cache被称为“缓存的 热数据”,也就是可能会高频使用的数据)
- 简单来说,cache对内存的代码和数据,更具局部性原理,预读CPU内部,如果进程切换,cache就立即失效;新进程过来,只能重新缓存,所以线程的执行比进程快的原因主要是在这里,由于线程是在进程里地,所以线程切换的时候cache不会失效,所以线程切换效率远高于进程切换
- 所以大部分人理解的线程切换比进程快是不需要切换地址空间和页表,但这个切换的影响不大,最主要的还是后面的cache缓存的机制,线程就是巧妙地利用了缓存来提升切换效率
四,线程周边概念
4.1 线程的数据共享
线程是共享进程数据的,但也有自己的一部分数据:
- 线程ID
- 一组寄存器:存储每个线程的上下文数据
- 栈:每个线程都有自己的临时数据,需要压栈和出栈
- errno错误码:C语言提供的全局变量,线程都有自己的
- 信号屏蔽字
- 调度优先级
其中最重要的就是:①一组寄存器 ②栈,这两个最终体现的是线程的动态特性
- 一组独立的寄存器,可以体现线程是被独立调度的
- 独立的栈:能够保证线程之间的运行是不会出现执行流错乱的情况的,因为栈里存的是运行时数据,每个线程都要有自己独立的栈区
4.2 线程的优点
- 创建一个新线程的代价要比创建一个新进程小得多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
- 线程占用的资源要比进程少很多,能充分利用多处理器的可并行数量
- 在等待慢速IO操作结束的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- IO密集型应用,为了提高性能,将IO操作重叠,线程可以同时等待不同的IO操作
计算密集型:执行流的大部分任务,主要以计算为主。比如加密解密、大数据查找等。
IO密集型:执行流的大部分任务,主要以IO为主。比如刷磁盘、访问数据库、访问网络等。
4.3 线程的缺点
- 性能损失: 一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
- 健壮性降低: 编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说,线程之间是缺乏保护的。
- 缺乏访问控制: 进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。也正是因为缺乏访问控制,才有了“线程安全”这个大板块,后面会有一篇单独的文章来详细解决线程安全问题
- 编程难度提高: 编写与调试一个多线程程序比单线程程序困难得多。
4.4 线程异常
- 单个线程如果出现除零、野指针等问题导致线程崩溃,进程也会随着崩溃
- 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出
4.5 线程用途
- 合理的使用多线程,能提高CPU密集型程序的执行效率
- 合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边吃饭一边刷视频,就是多线程运行的一种表现)
五,一些问题解答
如何理解将资源分配给各个线程?
- 线程目前的分配资源的方式,本质就是划分地址空间范围,简单来说就是分配代码和数据
- 代码也有地址,并且也是虚拟地址,假设我们在C语言中定义10个函数,每个函数地址不一样,所以只需要把每个函数交给各个线程运行,就是天然地做好了地址空间的划分,这叫做线程的代码和数据分离,我们不需要做任何事
既然线程优点这么多,那么是不是线程越多越好?
不是,CPU线程的切换虽然成本很低,但不是没有成本,而且当线程太多时,计算机的效率会变低,因为会占用CPU的资源执行线程,而导致其他进程的执行速度变慢,毕竟计算机还是以进程为主的
如何理解我们曾经学的进程呢?
- 以前的概念是:内部只有一个执行流的进程,现在的概念:内部有多个执行流,以前的概念是现在概念的子集,只有一个执行流是多个执行流的特殊情况
- 操作系统以进程为单位,给我们分配资源,只是当进程创建时,只有一个执行流罢了,所以进程的概念和线程的概念高度相似,以前学的是进程的“特殊情况”,现在学的一个进程有多个执行流才是“特殊情况”
- task_struct以现在的概念来说,就是进程内部的执行流
相关文章:
Linux系统编程——线程基本概念
目录 一,关于多线程 二,重新理解进程 三,线程VS进程 四,线程周边概念 4.1 线程的数据共享 4.2 线程的优点 4.3 线程的缺点 4.4 线程异常 4.5 线程用途 五,一些问题解答 如何理解将资源分配给各个线程&…...
【HALCON】如何实现hw窗口自适应相机拍照成像的大小
前言 在开发一个喷码检测软件的时候碰到相机成像和hw窗体的大小不一致,hw太小显示不完全成像的图片,这使得成像不均匀,现场辨别起来比较不直观,因此需要对其进行一个调整。 解决 省略掉读取图片的环节,我们只需要将…...
【Spring cloud】 认识微服务
文章目录 🍃前言🌴单体架构🎋集群和分布式架构🌲微服务架构🎍微服务带来的挑战⭕总结 🍃前言 本篇文章将从架构的演变过程来简单介绍一下微服务,大致分为一下几个部分 单体架构集群和分布式架…...
一个pdf分割成多个pdf,一个pdf分成多个pdf
在数字化办公和学习中,pdf格式因其良好的兼容性和稳定性而受到广泛欢迎。但有时候,我们可能需要将一个大的pdf文件分割成多个小文件,以便于分享、打印或编辑。今天,我就来教大家几种简单有效的方法,让你轻松实现pdf文件…...
rtsp client c++
直接上代码:源码 void doRtspParse(char *b) {std::vector<std::string> res;char *ptr b, *ptr1 nullptr;while ((ptr1 strstr(ptr, "\r\n"))) {res.push_back(std::string(ptr, ptr1 - ptr));ptr ptr1 2;}int len ptr - b;b[len - 1] \0;…...
实现好友关注功能的Feed流设计
摘要 在社交网络应用中,Feed流是展示好友动态的核心功能。本文将探讨如何设计一个Feed流系统,以实现好友关注和动态展示的功能。 1. Feed流的基本概念 Feed流是用户在社交网络中获取信息的一种方式,通常按照时间顺序展示好友或感兴趣的用户…...
【STM32修改串口波特率】
STM32微控制器中的串口波特率调整通常涉及到USART(通用同步接收器/发送器)模块的配置。USART模块提供了多个寄存器来设置波特率,其中关键的寄存器包括BRR(波特率寄存器)和USART_CR1(控制寄存器1)…...
印章谁在管、谁用了、用在哪?契约锁让您打开手机一看便知
“印章都交给谁在管”、“哪些人能用”、“都有哪些业务在用”…这些既是管理者最关心的印章问题也是影响印章安全的关键要素。但是公司旗下分子公司那么多,各类公章、法人章、财务章、合同章一大堆,想“问”明白很难。 契约锁电子签及印控平台推出“印章…...
[C++初阶]vector的初步理解
一、标准库中的vector类 1.vector的介绍 1. vector是表示可变大小数组的序列容器 , 和数组一样,vector可采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大…...
【等保2.0是什么意思?等保2.0的基本要求有哪些? 】
一、等保2.0是什么意思? 等保2.0又称“网络安全等级保护2.0”体系,它是国家的一项基本国策和基本制度。在1.0版本的基础上,等级保护标准以主动防御为重点,由被动防守转向安全可信,动态感知,以及事前、事中…...
VMware中的三种虚拟网络模式
虚拟机网络模式 1 主机网络环境2 VMware中的三种虚拟网络模式2.1 桥接模式2.2 NAT模式2.3 仅主机模式 3 网络模式选择及配置NAT模式3.1 VMware虚拟网络配置3.2 虚拟机选择网络模式3.3 Windows主机网络配置 4 配置静态IP 虚拟机联网方式为桥接模式,这种模式下&#x…...
深度学习基准模型Transformer
深度学习基准模型Transformer 深度学习基准模型Transformer,最初由Vaswani等人在2017年的论文《Attention is All You Need》中提出,是自然语言处理(NLP)领域的一个里程碑式模型。它在许多序列到序列(seq2seq…...
如何实现公网环境远程连接本地局域网宝塔FTP服务远程管理文件
文章目录 前言1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固定FTP地址连接 💡推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。…...
dledger原理源码分析系列(一)-架构,核心组件和rpc组件
简介 dledger是openmessaging的一个组件, raft算法实现,用于分布式日志,本系列分析dledger如何实现raft概念,以及dledger在rocketmq的应用 本系列使用dledger v0.40 本文分析dledger的架构,核心组件;rpc组…...
Github 2024-07-05开源项目日报 Top10
根据Github Trendings的统计,今日(2024-07-05统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6TypeScript项目2Jupyter Notebook项目1Dart项目1C++项目1免费API集合 创建周期:2900 天开发语言:Python协议类型:MIT LicenseSta…...
WHAT - React useEffect 依赖的 Object.is
目录 一、背景二、Object.is 的语法三、Object.is 的行为四、总结 一、背景 在 https://react.dev/reference/react/useEffect 中我们了解到: React will compare each dependency with its previous value using the Object.is comparison. 接下来我们学习一下 Ob…...
【Java EE】Spring IOCDI
Spring IOC & DI 文章目录 Spring IOC & DI一、Spring是什么?二、IOC(控制反转)2.1 通俗理解2.2 造汽车的例子理解IOC2.3 IOC详解1. 获取Bean2. 方法注解——Bean1. 应用场景:2. 应用方法:3. 注意要点: 特别注意: 四、DI4…...
【FreeRTOS】同步互斥与通信 有缺陷的同步示例
目录 1 同步互斥与通信1.1 同步互斥与通信概述1.2 同步与互斥的概念1.3 同步的例子:有缺陷1.4 freertos.c源码3. 互斥的例子:有缺陷4. 通信的例子:有缺陷5. FreeRTOS的解决方案 1 同步互斥与通信 1.1 同步互斥与通信概述 参考《FreeRTOS入门…...
Lambda表达式讲解
简介: Lambda表达式的使用场景非常广泛,主要包括函数式编程、集合操作、排序、线程编程、GUI事件处理、数据处理、Web开发等。 函数式编程:Lambda表达式是函数式编程的重要特性,可以用于替代传统的匿名内部类,简化代码,提高可读性。 集合操作:Lambda表达式可以与集合…...
深入了解Linux中的dnsmasq:配置与优化指南
目录 安装dnsmasqUbuntu/DebianCentOS/RHELFedora 配置dnsmasq基本配置高级配置 启动和测试dnsmasq优化dnsmasq性能优化安全性优化 常见问题与故障排除无法解析域名DHCP分配失败 在Linux系统中, dnsmasq 是一个轻量级的网络服务,主要用于提供DNS缓存和D…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
