Linux 多线程 ( 多线程概念 )

这篇具有很好参考价值的文章主要介绍了Linux 多线程 ( 多线程概念 )。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux线程概念

什么是线程?

  1. 在一个程序里的一个执行路线叫做线程 thread ),更准确的定义为:“线程是一个进程内部的控制序列"。
  2. 一切进程至少有一个执行线程。
  3. 线程在进程内部运行,本质上是在进程地址空间中运行。
  4. 在linux系统中,CPU看到的PCB比传统的进程更加轻量化。
  5. 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。

我们在以前所学习的进程知识中,一个进程由进程控制块(task_struct),进程地址空间( mm_struct ) ,页表,页表与进程地址空间,物理内存的映射为关系构成。

Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器

每一个进程都有自己独有的进程地址空间和页表,对应的映射关系,所以我们在创建进程时需要耗费大量的时间,空间。

但是,对于Linux系统,如果我们在创建一个进程后只创建task_struct,并且这些task_struct共享进程地址空间,页表等相关资源,图示如下。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器
由于这些task_struct指向同一块进程地址空间和页表,所以它们所看到的资源都是一样的,我们可以让这四个task_struct执行不同的代码区域(栈区,堆区等以上区域),换句话说,我们之后创建出来的3个task_struct都可以同时执行自己的代码,从而完成”并发“。像这样,我们把这样的一份task_struct称这为”线程“。

  • 其中每一个线程都是当前进程里面的一个执行流,也就是我们常说的”线程是进程内部的一个执行分支“。
  • 线程在进程内部运行,本质就是线程在进程地址空间内运行,也就是说曾经这个进程申请的所有资源,几乎都是被所有线程共享的。
  • 线程比进程粒度更细,因为执行的代码和数据也更小了。
  • 线程调度的成本更低了,因为它在调度的时候,核心数据结构(进程地址空间和页表都不用切换了)

windows下的线程和Linux下的线程区别

Linux其实并没有真正对线程创建特定的数据结构

  • 线程本身是在进程内部运行的,操作系统中存在大量的进程,一个进程内又存在一个或多个线程,因此线程的数量一定比进程的数量多(线程 : 进程 一定是n : 1),当线程的数量足够多的时候,很明显线程的执行粒度要比进程更细。
  • 对于这么多的线程我们OS需要对其做管理(先描述,再组织),在大部分的OS中,线程都有一个tcb。如果我们的系统实现的是真线程,比如说windows平台,它就要分别对进程和线程设计各自的描述的数据块(结构体),并且很多线程在一个进程内部,所以还要维护线程tcb和进程pcb之间的关系。所以这样写出的代码,其tcb和pcb两个数据结构之间的耦合度非常复杂。但是对于Linux来说,在概念上并没有进程和线程的区分,只将task_struct叫做一个执行流,所以对于Linux来说,PCB和TCB为同一种。

Linux中使用pcb模拟tcb的优势:

  • 不需要单独设计tcb了。
  • 不用维护tcb和pcb之间的关系。
  • 不用打再编写调度算法了。

在Linux中,CPU是否能够识别当前调度的task_struct是进程还是线程?

不能,因为CPU只关心一个一个独立的task_struct(执行流),无论进程内部只有一个执行流还是有多个执行流,CPU都是以task_struct为单位进行调度的。只是这里的task_struct只执行一部分代码和数据,但也并不妨碍CPU执行其他执行流。

图示如下:
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器

理解修改常量区

字符串常量区在代码区和已初始化数据区之间的,如果它不可被修改,那它是如何加载到物理内存呢?如何保证它不可被修改的?

比如当我们尝试修改字符串,字符串常量区经过页表的映射到物理内存,当它从虚拟地址到物理地址转换的时候,它是只读的,所以RWX权限为R,所以尝试在修改的时候直接在页表进行拦截,并结合MMU硬件转换,识别到只读但尝试修改的异常,发出信号,随后OS把此进程直接干掉。

如今,有了线程的引入,如何重新理解之前的进程?

我们红色方框框起来的内容,我们把这个整体叫做进程。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器

曾经我们理解的进程 = 内核数据结构 + 进程对应的代码和数据,现在的进程,站在内核角度上看就是:承担分配系统资源的基本实体。所有进程最大的意义是向系统申请资源的基本单位

因此,所谓的进程并不是通过task_struct衡量的,还需要创建地址空间、维护页表,然后在物理内存当中开辟空间、构建映射,打开进程默认打开的相关文件、注册信号对应的处理方案等等。

我们之前接触的进程内部只有一个task_struct,说明该进程内部只有一个执行流,也称之为”单执行流进程“。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器
如果进程内部有多个执行流,我们称之为"多执行流进程"。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器

  • Linux中,CPU实际上看到的task_struct实际上要比传统的task_struct更加轻量化,当进程只有一个执行流,那就说明等于OS内的进程,但是如果进程有多个执行流,那就说明该线程<其他OS内传统的PCB,CPU拿到的是进程中多执行流中某一个PCB,这某一个PCB并没有单独创建特定的数据结构,从宏观上,所以Linux下的进程统一称之为: 轻量级进程。
  • 线程(一个执行流)是CPU调度的基本单位。

原生线程库pthread

在Linux中,站在内核角度没有真正意义上线程相关的接口,但是站在用户角度,如果想创建线程,而不是只能用fork函数,所以提供了pthread原生线程库。

二级页表

二级页表引入

以32位平台为例,在32个比特位中一共可以存在2^32个地址,如果由虚拟地址空间通过页表映射到物理内存中,那么一个页表就需要2 ^32个表项存储地址。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器
并且,每一个表项除了要保存的虚拟地址以及物理地址这里就大概需要8字节,并且还需要保存一些权限信息,那么一个表项大概需要10个字节,那么最后意味着存储一张页表OS需要2^32 * 10个字节,那么也就是40GB。
Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器
可是,这远远超过了在32位平台下4GB的内存。

二级页表

实际上,OS在64位平台上是多级页表,在32位平台上是二级页表。

这里以32位平台为例,虚拟地址通过二级页表映射关系如下:

  1. 选择虚拟地址的前10个比特位在页目录中查找,通过映射关系找到对应的页表。
  2. 再选择虚拟地址的10个比特位在对应的页表中查找,通过映射关系找到对应的页框的起始地址。
  3. 最后将虚拟地址的剩下12个比特位作为偏移量从对应页框的起始位置后进行偏移,页框起始地址 + 偏移量 = 物理内存中对应的字节数据。

Linux 多线程 ( 多线程概念 ),Linux操作系统,linux,运维,服务器
说明一下:

  • 物理内存是按照4KB单位进行划分的(每一个4KB单位叫做页框),可执行程序上也是被划分为4KB为一个单位为页帧,当可执行程序和加载到内存中时也是以4KB进行加载和保存的。
  • 如果一级页表有一张,那就说明有2^10个表项,进而表示有2 ^ 10个二级页表,并且1个表项 大概10个字节,那么总字节数便为2 ^ 10 * 10个字节,也就是10MB,这极大节省了空间。
  • 上面所述的映射过程,总共由页表和MMU硬件完成,其中页表为软件映射,MMU是一种硬件映射,OS由虚拟地址转换为物理地址采用的是软硬链接结合的方式。

上述页表的优势:

  • 进程虚拟地址管理和内存管理,通过页表 + page进行了解耦。
  • 页表分离了,可以实现页表的按需获取,没有用到的就不创建,进而节省了空间。

线程的优点

  • 创建一个新线程的代价要比创建一个新进程小得多。
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多,这里有两个核心原因:
  1. 线程切换是不需要切换页表和进程地址空间的,而进程与进程调度之间需要切换页表,进程地址空间
  2. CPU内部具有硬件L1~L3 cache缓存,在进程进行访问的时候,CPU提前就将目标代码和数据加载到CPU的缓冲区中,一个进程内部的执行流访问时就可以可以直接从缓冲区中读取,提高调度效率。但是如果进程间切换,因为进程具有独立性,cache立即失效,新进程执行的时候,只能重新对该进程预计执行的代码数据缓存。
  • 线程占用的资源要比进程少很多。
  • 能充分利用多处理器的可并行数量。
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务。
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现。
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

那么,一个进程中线程是不是越多越好?

不是,即便线程切换搜耗费的成本较低。但是如果线程过多,那么会造成线程之间的调度成本过大。文章来源地址https://www.toymoban.com/news/detail-708621.html

线程的缺点

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

线程异常

  • 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃,因为在Linux中线程就是进程的一部分。
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出。

到了这里,关于Linux 多线程 ( 多线程概念 )的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】操作系统的基本概念 {冯诺依曼体系结构,操作系统的基本概念,系统调用及用户操作接口,shell程序}

    现代计算机设计大都遵守冯·诺依曼体系结构: 截至目前,我们所认识的计算机,都是由一个个的硬件组件组成 输入单元:包括键盘, 鼠标,扫描仪, 磁盘,网卡等 存储器: 内存(提高数据读写速度,降低硬件成本) 中央处理器(CPU):含有运算器(算数运算,逻辑运算)和控

    2024年02月11日
    浏览(52)
  • 【Linux】冯诺伊曼体系结构|操作系统概念理解

    个人主页:🍝在肯德基吃麻辣烫 我的gitee:Linux仓库 个人专栏:Linux专栏 分享一句喜欢的话:热烈的火焰,冰封在最沉默的火山深处 本文进入Linux较为晦涩的概念——冯诺依曼体系结构和操作系统的理解。 冯诺依曼体系结构是我们日常计算机都遵守的一个整体架构,计算机

    2024年02月14日
    浏览(58)
  • 【Linux】冯诺依曼体系结构 && 操作系统 && 进程概念

    目录 一、冯诺依曼体系结构 二、操作系统  1、概念  2、设计OS的目的 三、进程  1、基本概念  2、描述进程-PCB  3、组织进程  4、查看进程和终止  5、通过系统调用获取进程标识符  6、通过系统调用创建进程-fork  7、进程状态  8、特殊进程    8.1 僵尸进程    8.2 孤儿进

    2024年02月10日
    浏览(59)
  • 【Linux】冯诺依曼体系结构和操作系统概念

    数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(运算器、控制器、存储器、输入设备、输出设备),这套理论被称为冯·诺依曼体系结构。 现代计算机发展所遵循的基本结构形式始终是冯·诺依曼机结构。这

    2024年02月02日
    浏览(55)
  • 【Linux】进程概念I --操作系统概念与冯诺依曼体系结构

    Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。 计算机是由两部分组成的: 硬件+软件 .与硬件相关的为 冯诺依曼体系结构 ,与软件相关的为: 操作系统 . 如今大多数计算机(笔记本,服务器等)大多数都遵守冯诺依曼体系结构.实际中

    2024年02月09日
    浏览(35)
  • 【Linux】进程概念(冯诺依曼体系结构、操作系统、进程)-- 详解

    1、概念 (1)什么是冯诺伊曼体系结构? 数学家冯·诺伊曼于 1946 年提出存储程序原理,把程序本身当作数据来对待,程序和该程序处理的数据用同样的方式储存。 冯·诺伊曼理论的要点是:计算机的数制采用二进制逻辑;计算机应该按照程序顺序执行。人们把冯·诺伊曼的

    2024年02月22日
    浏览(53)
  • 【运维】手把手教你在Linux/Windows系统使用Nginx部署多个前端项目【详细操作】

            需求:项目上线需要将前端的前台和后台部署在服务器上提供用户进行使用,部署在不同的服务器直接在服务器安装nginx即可。但是在内网安装还是有点麻烦,因为需要联网,如果是内网可以参考Linux安装Nginx并部署前端项目【内/外网-保姆级教程】_MXin5的博客-CSDN博

    2024年02月08日
    浏览(61)
  • 《Linux操作系统编程》 第十章 线程与线程控制: 线程的创建、终止和取消,detach以及线程属性

    🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐 🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬

    2024年02月11日
    浏览(90)
  • C++ Linux Web Server 面试基础篇-操作系统(四、线程通信)

    ⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨‍🎓。 如果觉得本文能帮到您, 麻烦点个赞 👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️ Qt5.9专栏 定期更新Qt的一些项目Demo

    2023年04月26日
    浏览(50)
  • 【Linux操作系统】多线程抢票逻辑——学习互斥量(锁)函数接口

    临界资源 : 多线程执行流共享的资源就叫做临界资源 。 临界区 :每个线程内部, 访问临界资源的代码,就叫做临界区 。 互斥 :任何时刻, 互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用 。 原子性 :不会被任何调度机制打断的操作

    2024年02月16日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包