【Linux】多线程:线程概念,线程与进程的区别与联系,多线程相较于多进程的优势

2024-09-05 06:12

本文主要是介绍【Linux】多线程:线程概念,线程与进程的区别与联系,多线程相较于多进程的优势,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、进程基本属性回顾

二、线程概念

三、操作系统为什么要引入线程—多进程和多线程的区别 

为什么多线程比多线程调度效率更快?

 四、线程的优点

 五、线程的缺点

六、线程异常


一、进程基本属性回顾

在学习线程之前,我们先来回顾一下进程的基本属性:

1、进程是一个可拥有资源的独立单位——即进程是系统资源分配的基本单位。一个进程能够独立运行,就必须拥有一定的资源,包括:存放程序正文和数据的磁盘、内存地址空间、运行时所需要的I/O设备、进程已经打开的文件、信号量等。

2、进程是一个可独立调度和分派的基本单位。每个进程在系统中均有唯一的PCB(在Linux系统中是task_struct),系统可以根据PCB来感知进程的存在,也可以根据PCB中的信息对进程进行调度,还可将断点信息保存在进程的PCB中 。反之,也可以利用PCB中的信息来恢复进程运行的现场。

正是因为进程具有以上基本属性,进程才成为了可以独立运行的基本单位,从而也构成了进程并发执行的基础。

二、线程概念

那么什么是线程呢?我们先引入如下概念:线程是进程的一个实体,是CPU调度和分派的基本单位!

到这里可能有同学会有疑问了:之前不是说进程是是一个可独立调度和分派的基本单位吗?现在怎么又说线程是CPU调度和分派的基本单位了?

其实在已经引入线程的操作系统中,就已经把线程作为CPU调度和分派的基本单位了!

在Linux系统当中,我们可以这么来理解进程和线程:进程是操作系统进行资源分配的基本单位,线程是CPU调度和分派的基本单位!

那我们如何理解之前所学的进程呢?我们之前所学习的进程中,其实只包含一个执行流,也就是一个线程!实际上,我们之前所学习的进程是:具有一个执行流的进程,而一个进程必须至少拥有一个线程!!! 

举个更通俗的例子:在我们国家中,家庭通常是政府进行资源分配的单位,则家庭可以视为进程,而一个家庭至少包含一个家庭成员,也可包含多个,且家庭成员共享家庭的资源,但家庭成员又有各自的隐私,因此可以将家庭成员视为线程。家庭成员各自的任务和活动(如工作、学习、娱乐)可能会不同,但都在共享的家庭资源框架内进行。这类似于线程在进程中执行不同的操作,虽然每个线程可能执行不同的任务,但都在同一进程的资源和环境下运行。增加一个新的家庭成员(比如增加一个子女)相对容易,家庭的资源和管理模式不会发生重大改变。这类似于创建新线程的开销很小,因为新线程与现有线程共享资源和环境。相比之下,创建一个新的家庭(即进程)需要更多的资源和管理成本。

通过上图我们可以大致了解到:

1、在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”。

2、线程在进程内部运行,本质是在进程地址空间内运行。线程就是进程中的一个执行单元,是进程的一部分一个进程至少有一个线程(主线程)可以创建多个线程来并行执行任务

3、透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。同一进程中的所有线程共享进程的资源,但它们的执行是独立的。线程有自己的执行路径,可以同时进行多项任务,从而实现并发。

4、进程的多个线程共享同一地址空间,因此代码段和数据段都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:文件描述符表、每种信号的处理方式、当前工作目录、用户 ID 和组 ID

【了解】:但是实际上,Linux操作系统并没直接创造“线程”这一具体的事物,而是通过创造“轻量级进程(Lightweight Process, LWP)”来实现线程的功能。

用户视角:Linux 使用 pthread(POSIX线程)库来提供线程创建和管理的接口。pthread 库为线程提供了标准化的 API,允许程序员创建和管理线程、进行线程同步等。

内核视角:在内核中,每个线程是一个进程,但具有某些共享资源。内核的调度器处理这些线程就像处理进程一样。

所以我们在Linux系统中编写程序时,我们所面对的是pthread库为我们提供的管理“线程”的方法,在内核中实际上是被当作轻量级进程(LWP)来处理的,因此我们称Linux中的线程为“用户级线程”。而在Windows操作系统中,内核为线程专门创造了TCB这一数据结构来对每个线程进行标识和管理,而这些操作都由Windows内核来进行管理,所以我们称之为内核级线程。 

所以在Linux内核看来,对线程的调度与管理实际上就是对进程的调度与管理,依然可以沿用进程调度的那一套算法。而Windows则需要单独为线程创造一套专属的数据结构与方法。

这也是为什么在 Linux 系统中:在 CPU 眼中,看到的 PCB 都要比传统的进程更加轻量化!

三、操作系统为什么要引入线程—多进程和多线程的区别 

实际上,线程的引入是为了更好的提高程序的并发程度。

在引入线程这一概念之前,程序的并发执行多由多进程进行实现。但是通过之前的学习我们知道:进程是系统资源分配的单位,当多个进程并发执行时,势必会为系统资源的分配带来压力!

使用多进程时,系统必须要进行如下操作:

1、创建进程:系统在创建一个进程时,必须为它分配其所必须的、除处理机以外的所有资源(如内存空间、I/O设备等),并创建对应的PCB。

2、撤销进程:系统在撤销进程时,必须先对其所占有的资源执行回收操作,然后再撤销PCB。

3、进程切换:对进程进行上下文切换时,需要保留当前进程的CPU环境,这一过程需要花费不少的处理机时间。

由于进程是资源的拥有者,因此在对进程进行管理时,操作系统必须付出较大的时空开销。这就限制了系统中所设置的进程的数目,而且进程的切换也不宜过于频繁,从而限制了程序并发程度的进一步提高。

因此为使多个程序能够更好的并发执行,同时又能减少系统的开销,线程就应运而生。线程的出现将进程的两个基本属性分割开来:从此进程仅作为拥有资源的基本单位,线程则成为了调度和分派的单位。因此,在使用多线程时,由于多线程共享所属进程中的资源,因此减少了资源的频繁切换。

但同时,线程也有属于自己的资源:

  1. :每个线程都有自己的独立的栈,用于存放函数调用时执行上下文的数据,如局部变量、函数参数等。栈是线程特有的,可以确保线程之间不受其他线程的影响。

  2. 一组寄存器的状态:线程执行时所使用的寄存器,例如,程序计数器、寄存器组等,每个线程都有自己的寄存器状态,这是独立于其他线程的。

  3. 线程ID:每个线程都有自己的线程标识符(Thread ID),可以在同一进程中的其他线程或同级的用户程序中进行线程间通信或同步时识别和引用。

  4. 执行上下文:线程的执行上下文包含其调用的特定状态,如寄存器状态、指令指针等。这些状态在上下文切换时被保存和恢复。

  5. 线程局部存储(TLS):线程局部存储是特定于线程的全局变量,允许每个线程拥有一个独立的副本,但此全局变量必须为内置类型,且需要在变量类型前使用__thread关键字。

  6. errno :在多线程程序中,errno 通常被实现为线程局部存储(TLS),每个线程有自己的 errno 副本,确保线程之间不会相互干扰。

  7. 信号屏蔽字:每个线程都有自己的信号屏蔽字,它决定了该线程是否响应某些信号。线程可以通过系统调用(如 sigprocmask)来设置或更改信号屏蔽字。
  8. 调度优先级:每个线程都有一个调度优先级,操作系统根据这些优先级来安排线程的运行。高优先级的线程通常会比低优先级的线程获得更多的 CPU 时间。

 如此,我们便不难回答:

为什么多线程比多线程调度效率更快?

1、共享资源:多个线程可以在同一个进程中共享资源,如堆栈、状态和数据。这意味着它们可以更快地访问同样的内存地址,减少了内存的访问时间。

2、上下文切换:线程的上下文切换通常比进程的上下文切换速度更快。因为线程共享了地址空间和大部分内核资源,所以切换线程所需的时间相比于进程要短。

3、缓存命中率:在多线程应用程序中,多个线程可以共享缓存中的数据,这可以提高缓存命中率。由于多个线程共享同样的数据,这意味着他们更有可能从高速缓存中读取数据,而不是从更慢的主存中读取。

缓存(Cache)是一种基于内存的高速数据存储技术,用于提高数据访问速度。缓存可以是硬件层面的,也可以是软件层面的。在计算机科学中,缓存主要用在CPU缓存中,即高速缓存。

4、减少系统调用:在多线程应用程序中,多个线程可以在同一个进程中共享相同的文件描述符和网络连接,这意味着它们可以重用同样的一些资源,而不是创建多个进程时必须重新打开资源。

5、减少地址空间开销:进程有它们自己的地址空间,而线程共享相同的地址空间,这意味着多个线程可以节省虚拟内存的开销。

 四、线程的优点

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

• 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多 • 线程占用的资源要比进程少很多

• 能充分利用多处理器的可并行数量

• 在等待慢速 I/O 操作结束的同时,程序可执行其他的计算任务

• 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实 现

• I/O 密集型应用,为了提高性能,将 I/O 操作重叠。线程可以同时等待不同的 I/O 操作

 五、线程的缺点

• 等候使用共享资源时会使程序的运行速度变慢,这些共享资源主要是独占性的资源,如打印机等。

• 对线程进行管理要求额外的CPU开销。线程的使用会给系统带来上下文切换的额外负担,当这种负担超过一定程度时,多线程的缺点会表现得较突出,比如用独立的线程来更新数组内每个元素。

•线程的死锁。即较长时间的等待或资源竞争,以及死锁等多线程症状。

•对公有变量的同时读或写。当多个线程需要对公有变量进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另外,当公用变量的读写操作是非原子性时,在不同的机器上,中断时间的不确定性会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误是程序员无法预知的。

六、线程异常

  1. 线程异常与进程崩溃

    • 线程在运行过程中如果发生异常,如除零错误、访问野指针等,通常会导致线程崩溃。这些异常可能会引发操作系统层面的信号(例如 SIGFPE 对于除零错误,SIGSEGV 对于访问非法内存),这些信号会触发进程的终止机制
    • 当一个线程崩溃时,通常会导致整个进程的崩溃。这是因为线程共享进程的地址空间和资源,线程的异常可能会破坏进程的整体状态,从而导致进程无法继续安全地运行。
  2. 信号机制

    • 当线程发生致命异常时,操作系统会发送信号到进程,这些信号可能会导致进程的终止。例如,除零错误可能触发 SIGFPE,访问非法内存可能触发 SIGSEGV。这些信号会通知操作系统对进程进行处理,通常会导致整个进程的退出。
    • 在某些情况下,可以使用信号处理机制来捕获这些信号,从而进行一些清理工作或记录日志,但通常情况下,如果信号表示严重错误,进程会被终止。

这篇关于【Linux】多线程:线程概念,线程与进程的区别与联系,多线程相较于多进程的优势的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138167

相关文章

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

Linux如何查看文件权限的命令

《Linux如何查看文件权限的命令》Linux中使用ls-R命令递归查看指定目录及子目录下所有文件和文件夹的权限信息,以列表形式展示权限位、所有者、组等详细内容... 目录linux China编程查看文件权限命令输出结果示例这里是查看tomcat文件夹总结Linux 查看文件权限命令ls -l 文件或文件夹

idea的终端(Terminal)cmd的命令换成linux的命令详解

《idea的终端(Terminal)cmd的命令换成linux的命令详解》本文介绍IDEA配置Git的步骤:安装Git、修改终端设置并重启IDEA,强调顺序,作为个人经验分享,希望提供参考并支持脚本之... 目录一编程、设置前二、前置条件三、android设置四、设置后总结一、php设置前二、前置条件

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

Linux之platform平台设备驱动详解

《Linux之platform平台设备驱动详解》Linux设备驱动模型中,Platform总线作为虚拟总线统一管理无物理总线依赖的嵌入式设备,通过platform_driver和platform_de... 目录platform驱动注册platform设备注册设备树Platform驱动和设备的关系总结在 l

linux批量替换文件内容的实现方式

《linux批量替换文件内容的实现方式》本文总结了Linux中批量替换文件内容的几种方法,包括使用sed替换文件夹内所有文件、单个文件内容及逐行字符串,强调使用反引号和绝对路径,并分享个人经验供参考... 目录一、linux批量替换文件内容 二、替换文件内所有匹配的字符串 三、替换每一行中全部str1为st