Linux->线程基本概念

news2024/12/27 13:17:29

目录

前言:

1. 线程的基本概念

2 线程的优点

3 线程的缺点

4 数据块大小为4KB大小的真正原因


前言:

        本篇文章讲解了线程与进程之间的区别和联系,线程的优缺点,还有内存的数据管理与磁盘之间的关系,虚拟内存到内存之间的匹配方式,以及页表的补充知识。

1. 线程的基本概念

        在学习线程之前我首先给大家引入一个概念:

1. 线程是一个执行分支,执行粒度比进程更细,调度成本更低。

2. 线程是进程内部的一个执行流。

3. 线程是CPU调度的基本单位,进程是承担资源分配的实体。

        首先我给大家展示一张单执行流的图:

 

        上图就是我们进程执行函数的方式,CPU调度这个进程,通过PCB找到这个虚拟内存,再通过这个虚拟内存和页表找到实际我们的数据存的物理内存位置。那么概念1,线程是一个执行分支,执行粒度比进程更低,应该如何理解呢?

        每一个进程都有自己的地址空间,内存,和其它资源等等,这一点毋庸置疑的,并且每一个进程都有自己独立的一套机制,它们之间相互独立,这也是我们之间学习的,而线程却是在进程内运行的,并且多个线程可以共享同一个进程的资源,如下图所示。

         也就是同一个地址空间被多个PCB所看到了,这是进程所不能实现的部分。那么这个时候就有一个问题了,线程的管理和组织方式是怎么实现的?总不可能是让它乱跑的吧。当然不可能,其实在Linux当中,对线程的管理方式被归为了进程PCB的那一套方案当中,因为在本质上,它们是几乎相同的,都是用来描述这个执行流执行的位置,内容,只是线程没有属于它自己的地址空间,页表而已,所以线程的管理也是PCB那一套,并且我们称这样的线程PCB为LWP轻量级进程。

        那么线程是一个执行分支应该怎么理解?其实不同的线程PCB都看到了同一个地址空间,那么它们就可以分别执行这个地址空间的不同的部分,不同于原来的单执行流的进程只能串行执行,多执行流可以并发执行同一份代码。关于这部分我在之后会附上代码为大家展示出来。

        那么线程的调度成本更低这一句话又可以怎么理解呢?

        首先,我们在学习进程的时候有讲过,一个进程替换的时候,CPU会读取新的PCB中的值,替换寄存器当中的值,还有地址空间也会跟着被改变。不过单单这些条件并不能体现出线程的调度成本更低这一概念,因为不管是替换寄存器的值还是替换地址空间,页表什么的都只是替换一个指针罢了,并没有减少什么调度成本。真正减少的部分其实是CPU当中的高速缓存cache的内容,我们知道,我们的计算机在执行的时候遵循一个局部性原理,那就是当我们在运行某一段代码的时候,操作系统会将这段代码周围的代码也加载进来,因为这一部分的代码都很大的概率会被访问到。所以如果是进程替换的话,那没的说,只能逐步替换chche当中的内容,但是如果是线程呢?因为能够看到同一份的资源,所以大概率cache当中的内容不需要被替换,所以真正减少调度成本的地方在这里

         对于第一个概念的解释相信大家也理解了,那么又如何理解第二个概念呢?线程是进程内部的一个执行流。对于前面的理解,我们已经知道了一个线程有自己的PCB,那么为什么要说它是进程内部的一个执行流呢?这个问题很简单,其实单独只有线程是不能运行起来一个程序的,因为它没有自己的地址空间,它用的是进程的地址空间,也就是我们看到的进程应该是如下图所示:

         线程的执行是基于进程的,所以才会引出第三个概念,线程是CPU的基本调度单位,进程是承担资源分配的实体这一概念。

        原来我们所了解的进程是CPU的基本调度单位,其实就是一个不完全的概念,因为当时的我们只知道一个进程只有一个执行流的概念,所以浅显的认为进程就是CPU的基本调度单位没有错误,但是在引入了线程之后,缺少的部分知识被补充了。

#include<pthread.h>
#include<iostream>
#include<unistd.h>

using namespace std;

void* task1(void* x)
{
    while(true)
    {
        sleep(1);
        cout << "我是线程1, 正死循环当中" << endl;
        
    }
}

void* task2(void* x)
{
    while(true)
    {
        sleep(1);
        cout << "我是线程2, 正死循环当中" << endl;
        
    }
}

int main()
{
    pthread_t t1,t2;

    pthread_create(&t1,nullptr,task1,nullptr);
    pthread_create(&t2,nullptr,task2,nullptr);

    while(true)
    {
        sleep(1);
        cout << "我是主线程, 正死循环当中" << endl;
        
    }
    return 0;
}

         OS通过LWP区别线程,LWP与PID相同的就是主线程,OS也是通过PID和LWP来判断是否需要重新加载数据,以及替换数据。

2 线程的优点

1. 创建一个新线程的代价要比创建一个新进程小得多
2. 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
3. 线程占用的资源要比进程少很多
4. 能充分利用多处理器的可并行数量
5. 在等待慢速 I/O 操作结束的同时,程序可执行其他的计算任务
6. 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
7. I/O 密集型应用,为了提高性能,将 I/O 操作重叠。线程可以同时等待不同的 I/O 操作。

         由于线程本身只需要构建一个PCB,而不是像进程一样需要创建对应的地址空间等数据,它的代价必然比进程要低,而且在进行线程切换的时候,OS识别出来了这个PCB与前一个PCB属于同一个进程当中,减少了很多的替换操作,由于线程不需要额外开辟空间存放地址空间,所以消耗的资源必定比进程要小。一个进程有多个线程,CPU又是多核处理器,那么一个进程就能够充分的使用这些处理器。

        对于第五点来说,其实举一个例子来说就是我们下载视频时的一边下载一边观看的操作,下载和观看必然是属于两个执行流,又因为线程能够直接共享同一份地址空间,那么边下边看的操作就很容易实现。不过这一点对于进程之间也是能够实现的,因为一个进程进行下载,然后将下载的数据通过进程间通信方式传递给另外一个观看视频的进程当中也是能行的,所以这个优点体现的并不明显。

        对于第六和第七点来说,其实就是把一个执行流分化成为多个执行流,并发执行同一个程序,加快操作的完成时间,我们知道CPU通过时间片来切换PCB,如果我们一个进程的PCB多了,那么执行它的时间也多了,完成的速度当然也会跟着增加。不过有一点还是需要注意的,如果计算机本身只有几核,开辟的线程也不要太多了,因为你开辟再多的线程,真正能够执行的线程也就那几个,甚至多的线程还会导致调度成本的增加,虽然线程的调度成本低了,但也不是说直接没有了。

3 线程的缺点

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

         性能的损失其实就是我在线程的有点当中说的,如果开辟的线程数量不合适,那么最终会导致我们的调度成本增加。

        线程的健壮性降低其实就是一个线程执行错误时,会导致整个进程的崩溃,因为线程属于进程,线程的错误就是进程的错误,而线程导致的异常信号其实就是进程的异常信号。

        对于缺乏访问控制这一部分现在无法给大家讲清楚,这涉及到了原子性的问题,之后的文章我会为大家讲解的。还有最后一点其实是因人而异的,因为有的人熟悉多线程编写程序,有的人喜欢多进程编写程序。

4 数据块大小为4KB大小的真正原因

        如果有的小伙伴连数据块都不知道是什么的话,可以转看一下磁盘文件管理的相关内容。但是我还是会为大家回忆一下的:

        首先,在磁盘当中的每一个扇区都有512字节大小的空间,但是OS在读取这部分内容的时候会连续读8个这样大小的扇区,也就是4KB,这4KB大小的数据就是数据块。

        为什么要有数据块的原因是因为当我们要写数据进入磁盘当中,我们是进行100次IO操作更好呢,还是当数据加载完了然后一次就将数据写完更好呢?当然是一次写完更好,因为IO操作是内存与外设之间的交互欸,这个速度肯定是非常慢的,所以尽量的避免这样的操作才更好。这也是数据块出现的意义,如果每写1字节的内容就IO一次,我只能说,你的磁盘可真厉害,要是能满足现在计算机的需求,估计这个磁盘能买一套房。

        并且这个4KB大小是在存放在磁盘的时候就已经被规划好了,我们的OS的读取被规定成为了4KB大小,以后从磁盘找的时候,直接就找对应的4KB大小的数据,一起加载进内存当中。

        那么我现在有一个问题,如果我只要1个字节的数据是不是也会给我加载4KB大小的内容呢?这样做难道不是降低了我访问数据的速度吗?这个问题没有任何的问题,但是计算机基于一个局部性原理,什么意思呢?也就是计算机预测你访问了这个数据那么就有很大的概率访问这个字节周围的数据,那么他就一起将这一部分数据加载进来,它加快的是再次查找的数据,而不是单次查找的速度比较。

        所以对于磁盘和内存来说,它们的数据其实都是一块一块的被管理起来的,虽然看上去确实是连续存在的物理地址。那么这样一个一个的数据块必然是有相应的管理方式,也就是空闲页框链表,找到某一个空闲的位置,让后将数据块放入进去。

        上面的内容讲清楚了为什么我们的数据块要多加在数据的原因,但是没有讲清楚为什么是4KB的原因,对于这一部分我们需要从虚拟地址出发才能明白。

        大家在学地址空间的时候有没有一点疑问,那就是虚拟地址有4GB空间,在极限条件下,假设页表单项只有12字节大小,那么2^32*12等于48GB大小,一个页表就有48G,这不是开玩笑嘛,哪里有这么大的地方让他存起来。这必然是不可理的,但是注意到,我们32位的机器下的地址有4个字节,也就是32位,我们将他分为10+10+12,什么意思呢,前十位用来在1级页表当中找到二级页表,中间10位用来找到在内存中的数据块的起始位置,最后的12位呢?我们计算一下2^12是多少?4KB,用这4KB加上数据块基地址就能找到数据块当中的任意一个字节了。这才是4KB大小的最终原因

        如图所示:

         这样将一个地址分割了之后,页表在极限条件下最多也就2^20*12大小嘛,也就是几MB大小,放到内存当中存的下吗?很轻松的,并且正常情况下页表不可能达到这个条件,所以一般页表也就几KB左右,成功的解决了页表过大的问题。

        而且我们还知道,一个进程在加载时候不是将他的所有数据都加载到内存当中,而是一部分一部分的载入,那么这必然会导致可能页表找不到某一个数据块的问题,这个时候就会出现缺页中断的问题,那么OS就会去磁盘当中找到这个数据块,并加载进入内存,然后整个程序继续执行。

        页表当中并不是只有虚拟地址和物理地址,还有是否命中,读写执行权限,和用户内核权限的区别。那么这样就能在虚拟地址到物理内存的转换的时候发现代码是否出现了越权问题。

        举一个例子:

char* s = "hello world";

*s = 'H';

         这个代码在运行的时候一定会出现段错误的问题的,那么这是怎么发现的呢?

        首先我们知道s一定指向了一个地址,那么地址会通过页表找到真实的物理内存,虚拟地址到物理地址由一个硬件MMU实现,它在转换的时候他发现了你在对一个常量区数据进行修改,出现了越权的操作,那么他就会报错,OS识别到了MMU的错误,然后就会发送段错误的信号给对应的进程,进程收到了信号,对于这个信号的处理方式是让程序崩溃,这才是为什么在程序运行的时候能够发现有野指针的问题导致崩溃的原因


        以上就是我对这部分知识的全部理解了,希望对大家有帮助。

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

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

相关文章

阿里云服务器提供哪些操作系统和软件支持?是否与常用软件兼容?

阿里云服务器提供哪些操作系统和软件支持&#xff1f;是否与常用软件兼容&#xff1f;    阿里云服务器支持的操作系统   为了满足不同用户需求&#xff0c;阿里云服务器&#xff08;ECS&#xff09;提供了丰富的操作系统选择。以下是阿里云服务器支持的主要操作系统&#…

Linux 配置MySQL环境(三)

Linux配置MySQL环境 一、下载1. 官网下载MySQL2. 百度网盘快速下载MySQL 二、安装1、通过 Xftp 将 MySQL 安装包拷贝到 Linux2、解压缩3、安装 common、libs、client、server4、初步连接 三、卸载四、常用设置1. 修改 root 用户密码 五、使用新密码登录六、开启远程访问七、开放…

PHP设计模式21-工厂模式的讲解及应用

文章目录 前言基础知识简单工厂模式工厂方法模式抽象工厂模式 详解工厂模式普通的实现更加优雅的实现 总结 前言 本文已收录于PHP全栈系列专栏&#xff1a;PHP快速入门与实战 学会好设计模式&#xff0c;能够对我们的技术水平得到非常大的提升。同时也会让我们的代码写的非常…

OpenCV 笔记_5

文章目录 笔记_5特征点匹配DMatch 存放匹配结果DescriptorMatcher::match 特征点描述子&#xff08;一对一&#xff09;匹配DescriptorMatcher::knnMatch 特征点描述子&#xff08;一对多&#xff09;匹配DescriptorMatcher::radiusMatch 特征点描述子&#xff08;一对多&#…

Frontiers in Microbiology:DAP-seq技术在猪苓C2H2转录因子PuCRZ1调控菌丝生长及渗透胁迫耐受性机制研究中的应用

猪苓&#xff08;Polyporus umbellatus&#xff09;是一种可食用的蘑菇&#xff0c;也是我国常用的菌类药材之一&#xff0c;至今已有2000多年的药用历史&#xff0c;在《神农本草经》、《本草纲目》、《本草求真》等典籍中均有记载。猪苓具有利尿、抗菌作用&#xff0c;近年来…

SpringBatch从入门到实战(二):HelloWorld

一&#xff1a;HelloWorld 1.1 配置Job、Step、Tasklet Configuration public class HelloWorldJobConfig {Autowiredprivate JobBuilderFactory jobBuilderFactory;Autowiredprivate StepBuilderFactory stepBuilderFactory;Beanpublic Job helloWorldJob() {return jobBuild…

代码随想录算法训练营第五十九天|503.下一个更大元素II 42. 接雨水

目录 LeeCode 503.下一个更大元素II LeeCode 42. 接雨水 暴力解法 优化双指针法 单调栈法 LeeCode 503.下一个更大元素II 503. 下一个更大元素 II - 力扣&#xff08;LeetCode&#xff09; 【思路】 相较于前两道题目&#xff0c;这道题目将数组改为循环数组&#x…

python获取度娘热搜数据并保存成Excel

python获取百度热搜数据 一、获取目标、准备工作二、开始编码三、总结 一、获取目标、准备工作 1、获取目标&#xff1a; 本次获取教程目标&#xff1a;某度热搜 2、准备工作 环境python3.xrequestspandas requests跟pandas为本次教程所需的库&#xff0c;requests用于模拟h…

在读博士怎么申请公派访学?

作为在读博士生&#xff0c;申请公派访学是一项重要而有益的经历。下面知识人网将为您介绍一些关于如何申请公派访学的步骤和注意事项。 首先&#xff0c;您需要找到一个合适的公派访学机会。可以通过与导师、教授或其他相关人士进行交流来获取相关信息。还可以参考学术会议、研…

【Linux】linux | 服务响应慢、问题排查 | 带宽问题导致

一、说明 1、项目使用云服务器&#xff0c;服务器配置&#xff1a;5M带宽、4核、32G&#xff0c;1T&#xff0c;CentOS7 2、CPU、内存、磁盘IO都没有达到瓶颈&#xff0c;猜测是带宽问题 3、应用比较多&#xff0c;应用中间件&#xff0c;十几个差不多 4、同时在线人数30 5、已…

继承~~~

1&#xff1a;继承概述&#xff0c;使用继承的好处 1&#xff1a;什么是继承&#xff1f; Java中提供一个关键字extends&#xff0c;用这个关键字&#xff0c;我们可以让一个类和另一类建立起父子关系。 public class Student extends People{} Student称为子类&#xff08…

乘势而起:机载航电·显控显示系统仿真

改革开放以来&#xff0c;我国国民经济与科学技术取得了长足的发展&#xff0c;信息化、工业成熟度与自动化程度不断深化&#xff0c;极大地增强了国家的综合实力、在世界范围内显示了大国地位。在当前科技产业的发展和变革的历史性交汇期&#xff0c;“工业4.0”、“中国制造2…

iOS App 上架流程图文教学

在上架App 之前必须先准备好开发者帐号&#xff0c;但申请开发者帐号因法兰克早在之前已经申请好了&#xff0c;故就跳过此步骤&#xff0c;直接从产生凭证到上传App开始讲起。首先&#xff0c;要将自己辛苦写好的App 送审的话&#xff0c;则要依序做完下列几件事情即可。 在开…

NFT Insider #98:The Sandbox与Forkast Labs 达成合作,苹果的混合现实头显将增强游戏和元宇宙

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members(https://twitter.com/WHALEMembers)、BeepCrypto&#xff08;https://twitter.com/beep_crypto&#xff09;联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周…

对称加密DES加密算法原理、用户登录应用案例分享

更多知识 学习&#xff1a;https://www.processon.com/view/60504b5ff346fb348a93b4fa#map 目录&#xff1a; DES算法的工作原理DES算法的优点DES算法的缺点DES算法的应用场景DES算法性能分析用户登录实例总结 1. DES算法的工作原理 DES算法是一种对称加密算法&#xff0c;使…

定向写作模型CTRL,Conditional Transformer Language有条件的文本生成模型

定向写作模型CTRL 介绍 CTRL全称为Conditional Transformer Language有条件的文本生成模型&#xff0c;它始于Salesforce在2019年发布的论文《A Conditional Transformer Language Model for Controllable Generation》&#xff0c;该模型用于定向写作。论文地址如下&#xff…

双功能螯合剂:1777804-45-1,DOTA-(COOt-Bu)3-CH2-Ph-azide,的反应特点及其参数说明

​ 中文名称&#xff1a;1,1-二甲基乙基4-[(4-叠氮苯基)甲基] -7,10-双[2-(1,1-二甲基乙氧基) -2-氧乙基] -1,4,7,10-四氮杂环十二烷 -1-乙酸酯 英文名称&#xff1a;DOTA-(COOt-Bu)3-CH2-Ph-azide&#xff0c;DOTA-(COOt-Bu)3-CH2-Ph-N3 规格标准&#xff1a;1g、5g、10g CAS…

【电源设计】18650电池电源串并联设计——改变电压或容量

有时我们有需要改造电池电源的需要&#xff0c;比如增大容量&#xff0c;增大电压之类的&#xff0c;本文介绍18650锂电池&#xff0c;以及如何用18650锂电池串并联设计电源&#xff0c;达到增大容量或者增大电压的效果&#xff1a; 目录 一、18650锂电池基本知识&#xff1a…

腾讯的基础认证适合没经验、没专业知识的人吗?

IT行业可以说是现在最热门的行业之一了&#xff0c;很多人都会选择报考这个专业&#xff0c;同时还有很多没有基础的人&#xff0c;也会选择在毕业后继续教育&#xff0c;从而获得进入这一行的机会&#xff0c;可以说每个人都在内卷&#xff0c;技术和证书都需要拥有&#xff0…

这就是实力!京东资深架构师用实例详解Java虚拟机(源码剖析)

前言 Java是一门流行多年的高级编程语言&#xff0c;与其相关的就业岗位很多&#xff0c;但是最近几年却出现了用人单位招不到合适的人&#xff0c;而大量Java程序员找不到工作的尴尬局面。究其根本原因是岗位对Java开发技术的要求高&#xff0c;不但要会应用&#xff0c;而且…