从0开始linux(38)——线程(1)线程概念

欢迎来到博主专栏:从0开始linux
博主ID:代码小豪

文章目录

    • 进程与线程
    • 线程概念
    • 线程的优点
    • 线程的独立数据

进程与线程

如果要理解线程,那么进程将会时绕不开的点。首先我们回顾一下我们之前在进程章节当中是如何描述进程的?

进程=内核数据结构+代码和数据

代码和数据很好理解,我们在c/c++文件当中写的代码和数据,经过编译后形成的二进制可执行程序中,数据和指令都已二进制的形式保存在文件中。而内核数据结构指的是PCB(task_struct),mm_struct,vm_area_struct(进程地址空间),还有页表等等。这些存在于内核当中,描述与管理进程的相关数据结构。

那么线程是什么呢?

这里博主先从其中一个概念开始展开:线程是进程中的一个执行流,是进程的执行分支。

那么问题来了,什么是执行流呢?

我们可以将流看做是进程中连续的cpu指令,cpu在执行这些指令流,就叫做执行流。而根据进程地址空间,我们的cpu执行的指令、数据的地址,都是保存在进程地址空间当中的,而线程相当于是将这个进程地址空间的一部分切割开来,作为自己的地址空间,让cpu从中处理。那么此时进程就分为了两个执行流,继续执行主程序的,叫做主线程,而执行分支程序的,就是分支线程。

在这里插入图片描述

多说无益,我们尝试创建一个线程,创建线程用到的是C语言posix库中的函数pthread_create,关于这posix库是什么,我们在下一篇章节再说,pthread_create的函数原型如下:

 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

这些参数博主先不多介绍,首先start_routine是一个函数指针,即分支线程开始的函数地址(我们可以看成是线程的main函数)。pthread_t是线程号,线程号我们后面再说。我们只需要传入一个pthread_t的参数的地址即可。

那么程序如下:

void* Thread1Run(void* addr)//分支线程的入口函数
{while(true){std::cout<<"hello 我是线程1"<<std::endl;sleep(1);}
}int main()
{pthread_t tid;//创建分支线程pthread_create(&tid,nullptr,Thread1Run,(void*)"thread-1");while(true){std::cout<<"hello 我是主线程"<<std::endl;sleep(1);}return 0;
}

这段程序的逻辑如下:当进程运行时,此时内部没有分支线程,当执行pthread_create后,创建出一个分支线程。该线程执行Thread1Run函数的逻辑。此时进程1内部就出现了两个执行流,主执行流继续执行主函数的代码,而分支线程执行Thread1Run的代码。

运行结果如下:
在这里插入图片描述
从这里可以看出,主线程和分支线程是并行的,如果不是并行的,那么主线程压根不会执行pthread_create中的代码。

线程概念

如果线程可以并行,那么一定是需要linux系统对线程进行调度的,就像进程调度那样。那么既然linux要对线程管理起来,linux是如何管理线程的呢?老生常谈,linux管理进程,是通过创建内核数据结构,描述进程,接着通过内核数据结构来进行管理,我们将这个操作称为:先描述,再组织

那么线程又要如何描述呢?我们先来思考这么一个问题:我们需要线程有什么?首先,线程要有描述符,这样操作系统才能通过描述符找到要操作的线程;接着,线程要有执行的代码和数据,因此要有自己的地址空间;线程也可以通信、因此还要有文件描述符表fd_array。线程还要能接收到信号,因此要有pending表、block表、handler表。咦,这么看下来线程的内核数据结构好像和进程的内核数据结构一模一样啊?

没错,线程和进程用的内核数据都是一样的,即task_struct!!!!

这么一搞、我们就要对一个问题进行思考了。线程是什么?进程又是什么?

首先博主为进程和线程先下一个定义:线程是操作系统调度的最小单位、进程是承载分配资源的基本实体。

在我们上一个例子中已经看到,cpu会在线程之间进行切换调度,其原理和进程之间的切换调度类似。那么如何理解进程时承载分配资源的基本实体呢?首先我们来思考,一个进程需要什么资源?

首先进程要有地址空间吧,代码、数据、堆区、栈区,这些都是实打实存在于内存当中的,第二个,进程会打开文件吧,这些文件都也是要加载到内存当中的。这些就叫做资源。

那么线程有没有这些呢?答案是有!但是为什么说进程承载资源,而不是线程承载资源呢?这是因为,由线程申请的资源,都是放到进程名下的!如何理解这句话呢?我们在前面不是说了吗?将进程空间的一部分代码、数据分割给分支线程,线程就创建出来了,那么我们逆推一下:进程=主线程+分支线程

我们之前所见过的进程,是不是没有线程呢?非也,而是这些进程当中只有一个主线程,因此,我们在前面所说的进程调度,本质上也是线程调度,只是这个线程只存在一个而已。那么现在我们知道了,线程申请的一切资源都是放在进程名下的,这也意味着,线程之间使用的资源都是共享的即,同一进程下的线程使用的地址空间是相同的,使用的文件描述表也是相同的!!那么理解了这个,对于线程和进程的关系就很明了了。

我们可以以现实举个例子,比如我们从寝室走到教室,那么我们这个人就是一个进程,执行的任务就是到达教室,而我们的左脚、右脚、左腿、右腿则是进程下的线程,各自执行自己的程序,但是目的都是为了完成一个进程的任务。这些线程所使用的资源是共享的,即人体身上的能量,你总不能说你的左腿运动和右腿运动消耗的能量不属于同一个人吧?

在linux中,线程和进程其实并没有太大的区别,因此在linux当中,线程被称为轻量级进程,又称LWP(light weight process)。所谓的cpu对进程的调度,无论是进程还是轻量级进程,它们的权重没有任何区别。而且我们还能查到轻量级进程的属性,通过指令:ps -aL可以查看,但是考虑到让轻量级进程与进程之间有所区别,因此后面还是叫线程和进程。
在这里插入图片描述

线程的优点

  • 创建⼀个新线程的代价要比创建⼀个新进程小得多

我们fork出一个新进程,由于进程之前具有独立性,因此新进程要有自己的地址空间,要有自己的内核数据结构。而线程之间都是共享进程的资源的,因此创建一个新线程,只需要创建一个新的内核数据结构来描述轻量级进程就行。

  • 线程之间切换比进程之间切换的速度快

为什么呢?因为进程之间具有独立性,不同的进程,其代码数据不同,使用的进程地址空间也不同,页表不同,打开的文件也不同,这些东西都是要实打实加载到内存的。要加载,就是要让磁盘与内存之间做慢速I/O,因此速度变慢。

而且在CPU当中也有体现,不同的进程,其上下文也是不一样的,并不是说线程的上下文就相同,而是进程的上下文更复杂。因为在CPU当中存在两个东西,一个叫做TLB,一个叫做cache。这两个硬件都是用来做缓存的。TLB负责的是页表缓存,不同的进程拥有不同的页表,因此TLB肯定不能复用,因此切换进程的时候,TLB要重新作缓存,而线程之间由于使用的是相同的进程空间,因此在切换线程的时候,TLB就不用更新。

而cache我们还没认识过,现在我们就来讲讲。当一个进程运行时,我们要将进程中的数据和代码加载到内存当中,因为cpu与内存之间做交互的速度远快于cpu与磁盘做交互,但是cpu和内存之间的交互是最快的吗?当然不是,而是cpu与cache之间的交互才是最快的,因此,当cpu执行一个代码时,会将代码附近的所有数据都加载到cache当中,我们可以输入指令cat /proc/cpuinfo可以查看到cpu信息,其中就包括cache的大小
在这里插入图片描述

我们可以看到,一个cached可以缓存40M左右的数据,因此当cpu执行一个指令时,首先会查该指令的地址是否在cache当中,如果没有,再去内存当中找,顺便在将cache当中缓存的数据更新成,新执行的指令附近40M的数据。

那么为什么说cache能提高效率呢?这其实是一个概率性的问题,因为当计算机执行完一个代码后,其第二条代码,大概率在该代码的下一条。因此将代码附近的数据加载到cache中,可以大大减少cpu访问内存的次数。但是如果你能写出让cpu访问的代码不停跳转的程序,那么这个cache就相当于是负优化了,因为cache不仅没有让你减少cpu访问内存的频率,还要不停地加载内存中的数据到cache当中,这个时间只会更长。因此,这个基于cache缓存以提高cpu效率的方法,我们称为局部性原理。因此我们所写的代码和数据,要尽可能的减少不必要的跳转,以提升程序的运行速度。

那么我们回到进程,由于进程使用的内存空间是不同的,因此cache缓存的数据,是基本不可能让两个进程一起用的。因此切换进程的时候,cache当中的数据也要更新一下,这不也导致了cpu效率变慢了吗?而线程之间由于使用的资源都是在一个进程当中的,因此cache缓存大概率不用更新,因此切换线程所需要的时间开销也会变小。

但是线程并非完全没有缺点。

• 性能损失
◦ ⼀个很少被外部事件阻塞的计算密集型线程往往⽆法与其它线程共享同⼀个处理器。如果计
算密集型线程的数量⽐可⽤的处理器多,那么可能会有较⼤的性能损失,这⾥的性能损失指
的是增加了额外的同步和调度开销,⽽可⽤的资源不变。
• 健壮性降低
◦ 编写多线程需要更全⾯更深⼊的考虑,在⼀个多线程程序⾥,因时间分配上的细微偏差或者
因共享了不该共享的变量⽽造成不良影响的可能性是很⼤的,换句话说线程之间是缺乏保护
的。
• 缺乏访问控制
◦ 进程是访问控制的基本粒度,在⼀个线程中调⽤某些OS函数会对整个进程造成影响。

这里我们做简单的了解,博主在后面的章节当中还会继续说明

线程的独立数据

进程当中有哪些资源是线程之间共享的?而线程之间又有什么资源是不互通的?

共享的资源有:

  • 进程地址空间
  • 信号:所有线程对于信号的处理方式,都是一致的
  • 异常:如果一个线程出现了异常,那么整个进程都会崩溃
    其实这也很好理解,比如广西周某偷了电瓶,总不能说是我的手偷的,而不是总体偷的,进而免除惩罚吧?由于线程作为进程的一部分,所有的线程的目的,都是为了让进程完成某个任务,因此如果一个线程出现了异常,那么进程的任务还能完成吗?因此将进程中所有线程一起处理,才是正确的处理方法。
  • 文件描述符

不共享的资源有:

  • LWP:线程ID
  • 信号屏蔽字:即block表,虽然线程之间对待信号的处理方法一致,但是线程可以选择屏蔽掉啊
  • 线程的上下文数据:虽然使用的资源是相同的,但是它们具体执行的指令可不同,因此cpu在切换线程时,它们的上下文数据也要进行切换(只是切换线程的复杂度远低于切换进程。)
  • errno
  • 调度优先级

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

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

相关文章

Doge东哥wordpress主题

Doge东哥wordpress主题是一款专为中小型企业设计的WordPress外贸网站模板&#xff0c;它以其现代、专业且用户友好的界面&#xff0c;为企业提供了一个展示产品和服务的理想平台。以下是对该模板的详细描述&#xff1a; 首页设计概览 首页的设计简洁而不失大气&#xff0c;顶…

keil 5. Flash Timeout. Reset the Target and try it again.

使用官方STM32 ST-LINK Utility 烧写软件 KEIL 5, 设置DFP 包支持FLASH烧写算法 Keil 5, Flash Timeout. Reset the Target and try it again.-CSDN博客

MySQL源码编译

华子目录 下载源码包上传并解压安装cmake环境检测make编译make install安装 部署 下载源码包 下载相应源码包mysql5.7编译安装需要boost库&#xff0c;这里官网下载含boost的源码包https://downloads.mysql.com/archives/community/ 上传并解压 [rootmysql-node1 ~]# du -sh …

【Canvas与化学】枣红实心球钙元素图标

【成图】 120*120 大小图 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>钙元素图标 Draft2</title><style type&qu…

YOLOv8实战无人机视角目标检测

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对无人机目标数据集进行训练和优化&#xff0c;该数据集包含丰富的无人机目标图像…

私有库gitea安装

一 gitea是什么 Gitea是一款自助Git服务&#xff0c;简单来说&#xff0c;就是可以一个私有的github。 搭建很容易。 Gitea依赖于Git。 类似Gitea的还有GitHub、Gitee、GitLab等。 以下是安装步骤。 二 安装sqilite 参考&#xff1a; 在windows上安装sqlite 三 安装git…

【Anaconda】 创建环境报错:CondaHTTPError: HTTP 000 CONNECTION FAILED for url

问题描述 使用 Anaconda 创建环境时报错&#xff1a; CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/free/noarch/repodata.json.bz2> Elapsed: -An HTTP error occurred when trying to retrieve this URL. HTTP errors are o…

十一、快速入门go语言之接口和反射

文章目录 接口:one: 接口基础:two: 接口类型断言和空接口:star2: 空接口实现存储不同数据类型的切片/数组:star2: 复制切片到空接口切片:star2: 类型断言 反射 &#x1f4c5; 2024年5月9日 &#x1f4e6; 使用版本为1.21.5 接口 十、Java类的封装和继承、多态 - 七点半的菜市…

计算机的错误计算(一百七十)

摘要 回复一中学生来信&#xff0c;探讨 MATLAB 关于算式 的计算问题。 在计算机的错误计算&#xff08;一百三十二&#xff09;中&#xff0c;我们探讨了手持式计算器关于算式 的计算问题。一中学生来信询问该算式在数学软件中是否会出错。 例1. 在 MATLAB 中计算 . 首…

【科研】9如何高效阅读和理解学术论文

【科研】9如何高效阅读和理解学术论文 写在最前面一、为什么需要系统的阅读方法&#xff1f;二、阅读论文的11步方法三、实践示例四、常见问题解答五、结语 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光&#xff0c;感谢你的陪伴与支持 ~ …

RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者&#xff0c;因为业务需求&#xff0c;希望失败后重试一定次数&#xff0c;超过之后就不处理了&#xff0c;或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的&#xff0c;问了kimi&#xff0c;按它的方法配置之后&#xff0c;发…

计算机毕业设计Python+卷积神经网络股票预测系统 股票推荐系统 股票可视化 股票数据分析 量化交易系统 股票爬虫 股票K线图 大数据毕业设计 AI

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

《我的世界之武艺时代》——第2话

观众朋友们&#xff0c;大家好&#xff01;欢迎来到《我的世界之武艺时代》的精彩世界。在开始这段奇幻旅程之前&#xff0c;请您花几秒钟的时间为我们的作品点个赞&#xff0c;并将其收藏到您的书架中。这不仅是对我们创作者的最大支持&#xff0c;也是让更多人发现这部作品的…

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…

RPA:电商订单处理自动化

哈喽&#xff0c;大家好&#xff0c;我是若木&#xff0c;最近闲暇时间较多&#xff0c;于是便跟着教程做了一个及RPA&#xff0c;谈到这个&#xff0c;可能很多人并不是很了解&#xff0c;但是实际上&#xff0c;这玩意却遍布文末生活的边边角角。话不多说&#xff0c;我直接上…

oracle中删除指定前缀的表

近期接手做的项目&#xff0c;发觉数据库中有许多多余的表。究其原因&#xff0c;应该是同事贪图方便&#xff0c;将过去做过的项目复制粘贴&#xff0c;然后修修改改。包括数据库也是克隆过来的&#xff0c;然后又没有删除本项目多余的表&#xff0c;结果经过几个轮回&#xf…

【C#】C# resx方式实现多语言切换(静态切换)

1. 效果 中文界面 英文界面 2. 步骤 1. 添加resx文件 2. Form1.en-GB.resx内容 3. Form1.zh-CN.resx内容 4. Form1.cs修改&#xff08;重点&#xff09; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using Syste…

基于SpringBoot实现的编程训练系统(代码+论文)

&#x1f389;博主介绍&#xff1a;Java领域优质创作者&#xff0c;阿里云博客专家&#xff0c;计算机毕设实战导师。专注Java项目实战、毕设定制/协助 &#x1f4e2;主要服务内容&#xff1a;选题定题、开题报告、任务书、程序开发、项目定制、论文辅导 &#x1f496;精彩专栏…

Unity项目性能优化列表

1、对象池 2、检查内存是否泄露。内存持续上升(闭包、委托造成泄露) 3、检查DrawCall数量&#xff0c;尽量减少SetPassCall 4、尽量多的利用四种合批 动态合批(Dynamic Batching)静态合批(Static Batching)GPUInstancingSRP Batcher 动态合批消耗内存把多个网格组合在一起合并…

论文笔记 SliceGPT: Compress Large Language Models By Deleting Rows And Columns

欲买桂花同载酒&#xff0c;终不似&#xff0c;少年游。 数学知识 秩&#xff1a; 矩阵中最大线性无关的行/列向量数。行秩与列秩相等。 线性无关&#xff1a;对于N个向量而言&#xff0c;如果任取一个向量 v \textbf{v} v&#xff0c;不能被剩下的N-1个向量通过线性组合的方式…