Linux初阶——线程(Part1)
一、线程概念
1、如何理解线程
说到线程,那么我们就要回到进程了。
1.1. 再谈进程
对一个进程来说,它在内存中是这样的:
其中一个 task_struct 独享一个进程地址空间和一个页表。 而线程其实和进程差不多,是这样的:
其中多个 task_struct 共享一个进程地址空间,即共享进程地址空间里的正文代码、堆、变量等。所以,其实线程就是上图的一个个 task_struct , 然后这一个个 task_struct 分别执行进程代码的不同部分。所以也可以说因为进程的执行是由若干个线程的执行组成的。而也正因为线程执行的代码比进程的要少得多,因此我们称线程的执行粒度比进程要细得多。
所以,那真正的进程是什么样的呢?其实是这样的:
但是我们或许会产生这样一个疑问:那是不是以前进程的那些定义都错了呢,一个进程不是只有一个 PCB 吗,而在 Linux 里不就叫 task_struct 吗?其实这两者是不矛盾的,其实在只有一个 task_struct 的情况下,这个 task_struct 也是一个线程,只不过因为只有它一个,因此刚好独享了进程地址空间的全部资源罢了,所以进程的图就是图 1.1-a 样子了。所以,其实图 1.1-c 才是更普适的情况。
1.2. 理解线程
如果我们新建一个进程(包括 fork 一个子进程),那么操作系统就要为这个新进程开辟新的 task_struct、进程地址空间和页表。而如果我们新建一个线程,那么操作系统就只需要创建一个新的 task_struct 就可以了,然后和旧的 task_struct 一起共享页表和进程地址空间,然后不同的 task_struct 各自执行不同部分的代码。
所以,新建一个线程,操作系统除了会开辟空间当作 task_struct 外,就不会额外开辟其他空间了;但是新建一个进程,操作系统就会开辟新的 task_struct、进程地址空间和页表,简称新的系统资源。所以我们可以得出一个结论:操作系统执行代码是通过一个一个线程执行的,但操作系统只会对一个个进程分配系统资源(内存),并不会对一个个线程分配系统资源(内存)。
1.3. 线程与进程的关系
因为进程的执行是由若干个线程的执行组成的,但是操作系统是对进程发信号的;因此如果其中一个线程报错发信号,那么就会导致整个进程退出。那么既然整个进程都退出了,那进程里的全部线程绝对也全都退出了。所以我们可以得出一个结论:只要有一个线程挂了,那么整个进程里的线程也会全部挂掉。
2、二级页表(32 位)
当机器字长为 32 位时,内存里的地址只能用 32 位表示。但是我们知道如果进程地址空间只用了一级页表储存映射关系的话,而且进程地址空间总共是 4GB,因此页表的总大小也会是 4GB。可是这只是一个进程的,而且只是页表的大小,还没算代码和数据呢,如果算上这些的话,那么一个进程所占的空间就太大了,操作系统是不可能支持几十个进程载入内存的。所以如何缩小页表的大小呢?那么我们就要说说二级页表了。
2.1. 重新看待 32 位地址号
二级页表对 32 位地址号进行了拆分,采用了 10-10-12 的格式。高 10 位是指在哪一个二级页表;中 10 位是指在这个二级页表的哪一个内存块;而低 12 位是指这个内存块内的哪一行。
举个例子,如果地址为 0000000111 0000001000 000100101100,那么就说明要访问第 7 号二级页表中的第 8 号个内存块的第 300 号行。注意,所有的编号都是从零开始的。
2.2. 回到二级页表
得益于对 32 位地址的分段解读,虽然全部的二级页表的总行数还是和原来不用二级页表时的页表一样多;但通过二级页表,我们可以把原来的一级页表分成若干段,然后需要时就只把那一段的表加载进内存就行了;而不用像原来那样把整张一级页表加载进内存。这样就可以大幅减少页表所占用的内存空间了。
同时我们还可以发现,正是因为用了 10 位来表示表(一级页表和二级页表)中的编号,使得每个表的大小都是 4KB——刚好可以用一个内存块就可以装满了。因此操作系统开任何空间的大小都是按 4KB 的大小来开的,只不过我们可以用到的就不一定是 4KB 了。
3、线程周边概念
3.1. 执行流
因为 Linux 中,CPU 只认 task_struct,并不会认是不是进程或是不是线程,因此操作系统是没有进程或线程这一概念的,它只认 task_struct ,因此一个 task_struct 就是一个执行流了。
3.2. 主线程 & 新线程
其中 LWP(轻量型进程)等于 PID 的那个线程就是主线程,其他都是新线程。
二、线程的控制
1、线程的创建
1.1. clone 函数
参数介绍
- fn:新线程要执行那部分的代码的起始地址。
- stack: 该线程的线程栈,用于存储该线程的数据和变量,以及该线程的函数的栈帧。
这个函数是用来新建线程的,就如同 fork 函数一样。 但是,由于这个函数的参数是在太复杂了,因此线程库就把这个函数封装了起来;即在 pthread_create 函数和 pthread_join 函数的内部调用 clone 函数。
1.2. pthread_create 函数
参数介绍
- thread:输出型参数。把线程 ID 带出来。
- attr:输入型参数。输入该线程的属性,如果不输入就用默认属性。
- start_routine:就是 clone 函数的 fn。
- arg:输入型参数。输入 start_routine 函数的实参。
这个函数就是用来创建线程的。成功返回 0,失败返回其他值。
1.3. 线程 ID(pthread_t)
1.3.1. 为什么线程库要维护线程的概念
为什么线程库只要维护线程的概念,而不用维护线程的执行流(task_struct)?因为用户在用线程时,就指想获取线程有关的属性,比如线程 ID、线程的时间片、回调函数、独立栈等;但并不需要关注 task_struct 的编号、PID等那些 task_struct 的信息;因此线程库就没必要包含与 task_struct 的属性有关的东西了(不用描述 task_struct 了),取而代之的是,为了实现线程与执行流的概念,线程库中会把 tcb 与执行流建立连接,然后当线程要执行它的代码时,操作系统直接调用它的执行流就行了,但值得注意的是,此时用户并不关心操作系统调用的执行流,只会关心线程的属性!!!
1.3.2. 线程栈
由 clone 函数可知,创建一个线程时,不仅需要执行代码的起始地址,还要传一个栈的地址进去。而这个栈就是线程栈。
1.3.3. 线程 tid & 线程控制块 tcb
因为 Linux 是没有线程的概念的,只有 task_struct 的概念;因此在线程库内部就要维护线程的概念,而要维护线程的概念,就必须对多个线程进行管理,于是就要对线程进行“先描述,再组织”。而如何描述一个线程呢?其实 clone 函数和 pthread_create 函数就已经给出答案了:每个线程都要有自己的 ID,以及其他属性,还有自己的独享的栈。但这些都是在库内部维护的,因此如果要访问这些线程,那么就要把库加载到内存;但线程库是动态库,因此经过页表映射后是映射到进程地址空间的共享区里的;而线程这些概念是线程库在描述和组织,是线程库里的代码,因此线程的结构体和组织线程的数据结构、以及线程的栈都被加载到共享区里了,而不是进程地址空间的栈里。但主线程非常特殊,它的栈就是进程地址空间里的栈。
因为一个线程是由线程的属性(权限、时间片等)和线程栈组成的,因此在描述线程的结构体 tcb 肯定也是有这几个成分的。因此 tcb 的结构大概长这样:
而 tcb 的地址就是这个线程的 tid。
1.3.4. 线程的局部存储—— __thread 关键字
我们知道,全部线程是可以访问全局变量的。如果我线程想要一个私有的全局变量呢?那就要提到 __thread 关键字了。
__thread int count = 0; // 每个线程都有一个私有的 count 全局变量
以上面的例子为例,有了 __thread 之后,count 变量就不存在进程地址空间的数据区里了,而是存在每个线程 TCB 的线程局部存储区里了。
或许我们会想:那我在执行流的函数里定义个 count 变量不也一样吗?至于用这个私有的全局变量吗?其实,这个私有的全局变量同时适用于一个线程要执行多个函数这种情况。在这种情况下,该线程调用的所有函数都可以访问到这个 count;但如果只在执行流的函数里定义个 count 变量,该执行流调用的其他函数是无法访问这个 count 的。
注意:__thread 只能用于内置类型。
2、线程的回收
2.1. pthread_join 函数
参数介绍
- thread:输入型参数。线程的 tid
- value_ptr: 输出型参数。用来获取线程执行的函数的结果。如何获取呢?一般都会把线程执行的函数先强转成(void*)指针再返回。然后在给这个形参传 void* 指针变量的地址。
- 返回值:成功返回 0,错误返回其他值。
举个例子:
void* thread_run(void* arg)
{return (void*)100;
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, thread_run, nullptr);void* ret_val;pthread_join(tid, &ret_val);int ret = static_cast<int>(ret_val);return 0;
}
这样就可以获取线程执行的函数的结果啦!
2.2. 线程分离—— pthread_detach 函数
在默认情况下,新建的线程的释放都要显式调用 pthread_join 函数。但如果我们不关心线程运行的结果,我们可以在线程执行的函数调 pthread_detach 函数,告诉系统当线程执行完后可以自动回收线程。于是我们就不用显式地调用 pthread_join 函数来释放线程了。
参数介绍
- thread:线程的 tid。
- 返回值:成功返回 0,失败返回其他值。
相关文章:
Linux初阶——线程(Part1)
一、线程概念 1、如何理解线程 说到线程,那么我们就要回到进程了。 1.1. 再谈进程 对一个进程来说,它在内存中是这样的: 图1.1-a 其中一个 task_struct 独享一个进程地址空间和一个页表。 而线程其实和进程差不多,是这样的&…...
SpringBoot后端开发常用工具详细介绍——flyway数据库版本控制工具
文章目录 什么是flyway简介为什么要使用flyway 流程介绍整合springboot添加pom文件配置flyway向resource/db/migration添加sql文件 注意事项1. 迁移报错2. 迁移顺序 参考 什么是flyway 简介 为什么要使用flyway 我们在开发时往往会有这样一种情况: 进行软件开发…...
CSS揭秘:7. 伪随机背景
前置知识:CSS 渐变,5. 条纹背景,6. 复杂的背景图案 前言 本篇主要内容依然是关于背景的,无限平铺的背景会显得整齐美观,但又有些呆板,如何实现背景的多样性和随机性,是本篇的核心。 一、四种颜…...
SAP CODE DEMO:查找AL11 指定路径下文件中的内容
有时候需要查找某个具体的内容,在哪个文件内。数据量大的时候可以利用程序查找 选择界面: 路径,和文件名都可以模糊搜查 search string:你要查找的信息。 代码参考如下: report z00R010 NO STANDARD PAGE HEADING…...
【华为HCIP实战课程二十四】中间到中间系统协议IS-IS配置实战,网络工程师
一、IS-IS整体架构 将Level-1路由器部署在非骨干区域,Level-2路由器和Level-1-2路由器部署在骨干区域。 每一个非骨干区域都通过Level-1-2路由器与骨干区域相连! 1、在IS-IS中,每个链路可以属于不同的区域,OSPF中每个链路属于同一个区域 2、在IS-IS中,单个区域没有物理…...
【工具】新手礼包之git相关环境包括中文的一套流程{收集和整理},gitlab的使用
【工具】新手礼包之git相关环境包括中文的一套流程{收集和整理} git Git 详细安装教程(详解 Git 安装过程的每一个步骤) TortoiseGit 【TortoiseGit】TortoiseGit安装和配置详细说明...
篇章十一 打包构建工具
文章目录 一、gulp1. 流2. gulp 的作用3. gulp 的安装、检测和卸载 二、webpack1. 打包样式资源2. 打包 html 资源3. 打包图片资源4. 压缩 html 代码5. 生产环境基本配置 三、vite 打包构建工具,都是依赖于 node 环境进行开发,底层封装的内容就是 node 里…...
青少年编程与数学 02-002 Sql Server 数据库应用 06课题、数据库操作
青少年编程与数学 02-002 Sql Server 数据库应用 06课题、数据库操作 课题摘要:一、数据库的文件组成二、系统数据库三、创建数据库四、数据库配置1. 修改数据库文件大小和增长设置2. 添加或移除数据文件3. 设置数据库选项4. 配置数据库的恢复模型5. 管理数据库的访问权限6. 使…...
MacOS下载安装Logisim(图文教程)
本章教程主要介绍如何在MacOS系统中安装Logisim。 一、Logisim是什么? Logisim是一个用于电子逻辑门电路模拟的教育工具软件。它允许用户通过图形界面构建和测试复杂的数字逻辑电路,如加法器、解码器、编码器、寄存器、内存等,从而帮助学生理解计算机硬件的工作原理。 二、如…...
Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案
Flink CDC系列之:调研应用Flink CDC将 ELT 从 MySQL 流式传输到 StarRocks方案 准备准备 Flink Standalone 集群准备 docker compose为 MySQL 准备记录使用 Flink CDC CLI 提交作业 同步架构和数据更改路由变更清理 本教程将展示如何使用 Flink CDC 快速构建从 MySQ…...
一次元空间FullGC导致OOM问题分析
原文,作者:kkyeer 原文需要翻墙,所以转载。 现象 观测平台告警:FullGC次数大于阈值,5分钟内大于11次,频次大概1-2周有一次 告警后服务概率性会自动恢复,控制台打印 Exception: java.lang.OutOf…...
Web前端开发工具和依赖安装
各种安装: node.js https://nodejs.org/zh-cn/ 安装完node.js 可以使用npm,npm跟随nodejs一起安装 node --version 查看已安装node.js的版本,确认是否安装nodejs npm -v 查看npm版本npm install <Module Name> 安装模块 npm insta…...
【学习心得】远程root用户访问服务器中的MySQL8
一、Ubuntu下的MySQL8安装 在Ubuntu系统中安装MySQL 8.0可以通过以下步骤进行1. 更新包管理工具的仓库列表: sudo apt update 2. 安装MySQL 8.0,root用户默认没有密码: sudo apt install mysql-server sudo apt install mysql-client 【…...
lust变频器维修电梯变频器CDD34.014.W2.1LSPC1
LUST伺服在安装时须注意,不可有任何的铁屑、螺丝、导线等掉人驱动器内。在安装完成后应作基本的检测动作,如对地阻抗,和短路检测等。 所有的安装及使用事项需要符合安全规定,并且也需要符合当地的相关规定和灾害预防措施。DC BUS…...
跨越地域限制:在线原型设计软件的自由与便捷
网络原型设计软件因其便捷性和灵活性,在现代设计工作中扮演着至关重要的角色。与传统的桌面端软件相比,网络原型设计工具无需安装,不受地域限制,且兼容各种操作系统,无论是Linux、Solaris、Mac还是Windows,…...
flash-waimai:高仿饿了么外卖平台,使用他轻松打造自己的外卖平台
嗨,大家好,我是小华同学,关注我们获得“最新、最全、最优质”开源项目和工作学习方法 flash-waimai 是一个完整的外卖平台解决方案,包括手机端、后台管理端和 API 服务。该项目仿照了饿了么的外卖服务,为用户提供了一个…...
2.5 塑性力学—应变状态
个人专栏—塑性力学 1.1 塑性力学基本概念 塑性力学基本概念 1.2 弹塑性材料的三杆桁架分析 弹塑性材料的三杆桁架分析 1.3 加载路径对桁架的影响 加载路径对桁架的影响 2.1 塑性力学——应力分析基本概念 应力分析基本概念 2.2 塑性力学——主应力、主方向、不变量 主应力、主…...
1.机器人抓取与操作介绍-深蓝学院
介绍 操作任务 操作 • Insertion • Pushing and sliding • 其它操作任务 抓取 • 两指(平行夹爪)抓取 • 灵巧手抓取 7轴 Franka 对应人的手臂 6轴 UR构型去掉一个自由度 课程大纲 Robotic Manipulation 操作 • Robotic manipulation refers…...
六,Linux基础环境搭建(CentOS7)- 安装HBase
Linux基础环境搭建(CentOS7)- 安装HBase 大家注意以下的环境搭建版本号,如果版本不匹配有可能出现问题! 一、HBase下载及安装 HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“…...
《计算机网络网络层:连接虚拟世界的关键桥梁》
一、网络层概述 网络层在计算机网络中占据着至关重要的地位,它作为连接不同网络的关键层次,起着承上启下的作用。网络层的主要任务是实现网络互连,将数据设法从源端经过若干个中间节点传送到目的端,为分组交换网上的不同主机提供通…...
【AIGC】2024-arXiv-CtrLoRA:一种可扩展且高效的可控图像生成框架
2024-arXiv-CtrLoRA: An Extensible and Efficient Framework for Controllable Image Generation CtrLoRA:一种可扩展且高效的可控图像生成框架摘要1. 引言相关工作3. 方法3.1 准备工作3.3 有效适应新条件3.4 条件嵌入网络的设计 4. 实验4.1 实验设置4.2 与现有方法…...
立仪光谱共焦在玻璃上奥秘与应用
在现代工业和科学研究中,玻璃因其透明、坚硬和易加工的特性被广泛应用于各个领域。然而,玻璃的厚度测量一直是困扰业界的一大难题。传统的千分尺或电容式传感器虽然在一定程度上能满足生产需求,但在精度、效率以及适用范围上存在明显的局限。…...
【天气识别系统】Python+卷积神经网络算法+人工智能+深度学习+TensorFlow+算法模型训练+Django网页界面
一、介绍 天气识别系统,以Python作为主要编程语言,通过收集了4种常见的天气图像数据集(多云、雨天、晴天、日出),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练,最后得到一个识…...
MiniCTX:面向大语言模型定理证明的上下文相关基准测试系统
卡内基梅隆大学的研究人员推出MiniCTX,这是一个强大的基准测试系统,旨在通过整合前所未有的多重上下文元素(包括前提、先前证明、注释、符号以及导入和声明等结构组件)来彻底改变大型语言模型中定理证明能力的评估方式,…...
树莓派开发相关知识三PWM控制转速
基于树莓派PWM控制 控制L298N马达驱动转速 马达驱动转速 1、L298N电路图: 2、需要留意的有几点 INA~IND四个引脚分别控制OUTA-OUTD,即,INA高电平则OUTA有电。 ENA,ENB分别使能控制OUTA~OUTB以及OUTC~OUTD。 OUT口有VCC电压驱动…...
SpringBoot最常用的注解
1、RestController 作用:与Controller类似,但是RestController会自动将返回值转换为JSON格式。 2、RequestMapping 作用:用于映射请求URL和处理方法。 RequestMapping是Spring MVC框架中的一个核心注解,它用于映射HTTP请求和控…...
js 获取当前时间与前一个月时间
// 获取当前时间的毫秒数 var currentTimeMillis new Date().getTime();// 获取前一个月的Date对象 var dateLastMonth new Date(); dateLastMonth.setMonth(dateLastMonth.getMonth() - 1);// 获取前一个月的毫秒数 var timeMillisLastMonth dateLastMonth.getTime();conso…...
深度了解flink rpc机制(四) 组件启动流程源码分析
前言 目前已发布了3篇关于Flink RPC相关的文章,分别从底层通信系统akka/Pekko,RPC实现方式动态代理以及Flink RPC相关的组件做了介绍 深度了解flink rpc机制(一)-Akka/Pekko_flink pekko akka-CSDN博客 深度了解flink rpc机制&…...
C++基于opencv的视频质量检测--遮挡检测
文章目录 0.引言1. 原始代码分析1.1 存在的问题 2. 优化方案3. 优化后的代码4. 代码详细解读4.1. 输入检查4.2. 图像预处理4.3. 高斯模糊4.4. 梯度计算4.5. 计算梯度幅值和方向4.6. 边缘检测4.7. 计算边缘密度4.8. 估计遮挡程度4.9. 限定结果范围4.10. 返回结果 0.引言 视频质…...
手机玩潜水员戴夫?GameViewer远程如何随时随地玩潜水员戴夫教程
如果你是潜水员戴夫的忠实玩家,你知道如何在手机上玩潜水员戴夫吗?潜水员戴夫是一个以神秘蓝洞为背景的海洋冒险游戏。在这个游戏里你白天可以在美丽的大海里打鱼,晚上可以经营寿司店。现在这个游戏也能实现用手机随时随地畅玩了!…...
苏州做网站建设公司/最新的全国疫情
一、HTTP的缺点 到目前为止,我们已经介绍完HTTP,它具有相当优秀和方便的一面,但它也有不足之处,HTTP 主要有这些不足,例举如下。 通信使用明文(不加密),内容可能会被窃听 不验证通…...
网站建设方案项目书/小红书seo软件
一、是什么 在以前文章 (opens new window)中,我们了解到生命周期定义 生命周期(Life Cycle)的概念应用很广泛,特别是在经济、环境、技术、社会等诸多领域经常出现,其基本涵义可以通俗地理解为“从摇篮到坟墓”(Cradle-to-Grave)的整个过程 跟Vue一样,React整个组件…...
wordpress简体切换/网站推广软文
展开全部大四学生32313133353236313431303231363533e58685e5aeb931333433653933,应该先考研还是工作后再考研?这两种选择,哪一个更实惠?作出选择之前,这3个问题一定要考虑清楚。考虑复习效果一般情况下,多数…...
中国工程建设造价信息网站/北京seo实战培训班
有时我们在安装系统后,发现没有安装当前系统的内核源码在/usr/src/kernels目录下。其实很简单,是少安装了一个rpm包(kernel-devel); 安装上就可以了 有些软件安装没有问题,运行时就报错。(我今天…...
php网站开发师条件/重庆人力资源和社会保障网官网
Akaxin是一款开源免费的私有聊天软件,可以部署在任意服务器上,搭建自己的聊天服务器,供自己与朋友、用户使用。githubhttps://github.com/daychat/openzaly特性:单聊、群聊(含文字、图片、语音等)端到端的加密消息(服务端不可解密…...
在哪里可以做网站赚钱/如何制作一个宣传网页
2019独角兽企业重金招聘Python工程师标准>>> 之前用Redis2.x的时候就发现 jedisConnectionFactory.setDatabase(db); 这个方法已经过时了,不能用了,但是那时候没有用到这个功能,也就没在意,最近又更新了一下最新版本&a…...