【Linux系统化学习】线程概念

2024-03-03 23:52

本文主要是介绍【Linux系统化学习】线程概念,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

线程的概念

线程的引出

什么是线程

理解线程比进程更加的轻量化

线程的优点

现成的缺点

线程异常

线程用途

Linux进程VS线程

线程的简单现象


线程的概念

有关操作系统的书籍或者课本都会这样描述线程:

  • 线程是比进程轻量化的一种执行流
  • 线程是进程内部的一种执行流

线程的引出

线程的概念让我们先从之前的进程谈起

一个进程的产生,首先要将代码和数据从磁盘加载到内存中;然后创建虚拟地址空间和页表,让我们的虚拟空间和物理空间联系起来;最后操作系统给这个进程创建PCB,将PCB和虚拟地址空间建立联系,这样PCB通过虚拟地址空间和页表可以找到物理内存中可执行程序的代码。这样一系列创建进程的流程对于进程来说:地址空间是进程的资源窗口。

一个进程的出现从零到一,从无到有;需要创建PCB,申请资源空间,各种初始化,加载动态库,加载代码,各种映射;整个过程耗时耗力,成本非常高;有没有一种可能我们创建一种特殊的”进程“,只复用几经含有的进程的PCB进行创建PCB,指向这个已经含有进程的虚拟地址空间。通过各种方法把不共享的区域拆成几分,共享的保留。每个”进程“该执行自己的执行自己的,该共享的共享。将页表进行切割,实现区分。

和创建进程相比较,这个特殊的进程只需要创建一个PCB,创建非常的简单,没有各种初始化和加载,只参与进程资源的分配。非常的轻量化。在Linux操作系统中这个特殊的轻量化进程就是我们的线程。

什么是线程

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

因此线程的本质:

  • 线程是CPU调度的基本单位
  • 线程是承担系统资源的基本实体。

那么对于之前文章中的进程,是只含有一个执行流的进程,今天的进程含有多个执行流,每个执行流就是一个进程,也是一个线程。

理解线程比进程更加的轻量化

CPU对于一个进程的切换和一个进程的产生一样非常麻烦;需要替换页表,虚拟地址空间,代码等各种数据。而对于一个线程来说只需要替换PCB既可,线程通过对页表的切割;每个线程依然可以通过页表找到或者访问到自己的数据。其实这样的切换对于现在CPU的速度来说是可以忽略不计的。

首先我们要清楚局部性原理,对于CPU来说目前我们正在处理第10行代码有很大的概率接下来会处理第11行及以下的代码。根据冯诺依曼体系结构和木桶原理,CPU再对第11行代码进行处理的时候势必要从内存中重新加载代码。因此我们可以在CPU中添加一个缓存(cache),根据局部性原理,将接下来有很大概率被处理的代码预加载到这个缓存中即可;保存在缓存中的数据称为热数据。那么我们在回头来看切换一个进程,还需要将这个热数据进行切换,而线程则不需要。因此线程是比进程更加的轻量化。

线程的优点

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

现成的缺点

性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。

健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。

缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。

编程难度提高

编写与调试一个多线程程序比单线程程序困难得多

线程异常

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

线程用途

  • 合理的使用多线程,能提高CPU密集型程序的执行效率
  • 合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)

Linux进程VS线程

  • 进程是资源分配的基本单位
  • 线程是调度的基本单位

线程共享进程数据,但也拥有自己的一部分数据:

线程ID
一组寄存器
栈(动态运行)
errno
信号屏蔽字
调度优先级                                                                                                                                          硬件上下文(动态切换)

程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符表
  • 每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)
  • 当前工作目录
  • 用户id和组id

进程和线程的关系如下图:

线程的简单现象

  7 8 // 新线程9 void *ThreadRoutine(void *arg)10 {11     const char *threadname = (const char *)arg;12     while (true)              13     {14         std::cout << "I am a new thread: " << threadname << ", pid: " << getpid() << std::endl;15         sleep(1);                                                                                                                     16     }17 }18                  19 int main()20 {21     // 已经有进程了22     pthread_t tid;23     pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread 1");24                    25                   26                                                                      27     // 主线程28     while (true)29     {30         std::cout << "I am main thread"31                   << ", pid: " << getpid()  << std::endl;32         sleep(1);33     }                                  34     return 0;}

上面的代码我们在主线程中创建了一个线程,两个线程含有相同的PID;而主线程的PID和LWP是一样的;LWP(Light Weight Process)译为轻量级进程的意思。


今天对Linux下线程的概念的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!

这篇关于【Linux系统化学习】线程概念的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

基于Linux的ffmpeg python的关键帧抽取

《基于Linux的ffmpegpython的关键帧抽取》本文主要介绍了基于Linux的ffmpegpython的关键帧抽取,实现以按帧或时间间隔抽取关键帧,文中通过示例代码介绍的非常详细,对大家的学... 目录1.FFmpeg的环境配置1) 创建一个虚拟环境envjavascript2) ffmpeg-py

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

Linux系统中的firewall-offline-cmd详解(收藏版)

《Linux系统中的firewall-offline-cmd详解(收藏版)》firewall-offline-cmd是firewalld的一个命令行工具,专门设计用于在没有运行firewalld服务的... 目录主要用途基本语法选项1. 状态管理2. 区域管理3. 服务管理4. 端口管理5. ICMP 阻断

Linux实现线程同步的多种方式汇总

《Linux实现线程同步的多种方式汇总》本文详细介绍了Linux下线程同步的多种方法,包括互斥锁、自旋锁、信号量以及它们的使用示例,通过这些同步机制,可以解决线程安全问题,防止资源竞争导致的错误,示例... 目录什么是线程同步?一、互斥锁(单人洗手间规则)适用场景:特点:二、条件变量(咖啡厅取餐系统)工作流

Java中常见队列举例详解(非线程安全)

《Java中常见队列举例详解(非线程安全)》队列用于模拟队列这种数据结构,队列通常是指先进先出的容器,:本文主要介绍Java中常见队列(非线程安全)的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一.队列定义 二.常见接口 三.常见实现类3.1 ArrayDeque3.1.1 实现原理3.1.2

SpringBoot3中使用虚拟线程的完整步骤

《SpringBoot3中使用虚拟线程的完整步骤》在SpringBoot3中使用Java21+的虚拟线程(VirtualThreads)可以显著提升I/O密集型应用的并发能力,这篇文章为大家介绍了详细... 目录1. 环境准备2. 配置虚拟线程方式一:全局启用虚拟线程(Tomcat/Jetty)方式二:异步