【Linux】线程详解之线程概念

2023-11-11

前言

在我们的教材中,对线程给出以下的概念:

是进程内部的一个执行分支,在进程的内部运行,属于进程的一部分,比进程更加轻量化。

可能有的人看完之后都是懵的,什么叫在进程的内部运行,什么又是执行分支,为什么比进程轻量化,我们就带着这三个问题,重新来探究一下线程。

一、什么是线程

经过前边的学习,我们知道进程拥有一个PCB,在Linux中被称为task_struct,并且有一个进程地址空间,也有一个页表,通过页表指向物理内存,但是从今天开始,对进程的概念可能发生变化,这个我们后边来说,在Linux中,并没有真正的线程,而是使用进程的PCB来模拟线程,也就是说一个线程在创建时,只会去创建一个PCB,而这个PCB也指向主线程的虚拟地址空间,和其他线程一起共享内存的代码和数据。一个线程也被称为一个执行流,这是因为线程是被CPU调度的执行流,而一个进程就是分配系统资源的基本实体。

以我们的实际生活来类比,我们可以将操作系统比作中国,而每一个进程就是一个家庭,而每个家庭中的成员就是一个一个线程,家庭中的户主就是一个主线程,每个家庭是互不干扰的,这也就是进程是独立的,但是家庭中的成员是亲密的,他们可以共享代码和数据,因为一个进程中的线程组是指向同一个虚拟内存的。

在这里插入图片描述
下边给出线程的一些概念:

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

线程其实在进程的虚拟地址空间内,并且是进程的一个执行分支,所以说线程是一个进程内部的的控制序列。

2.一切进程至少都有一个执行线程

一个进程至少有一个执行线程,就像我们之前看到的进程一样,并没有创建线程,所以就只有一个线程,也就是只有一个PCB。

3.线程在进程内部运行,本质是在进程地址空间内运行

线程本质就是在进程地址空间内运行,与进程看到的是同一份地址空间。

4.在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化

现在的进程,是创建很多的PCB,但是只有一个地址空间,进程将数据和代码分配给每一个PCB,所以一个进程中可能有多个PCB,其实使PCB更加轻量化了。

5.透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流

os不需要再给线程实现一套调度算法,而是复用进程的调度算法,os只需要将进程的代码和数据分配给每一个线程就好了,这样线程就是进程中的一个执行流。

二、线程和进程对比

进程是是承担分配系统资源的基本实体,而线程是CPU进程调度的基本单位,是承担进程资源一部分的基本实体。

每个进程都具有独立性,但是可以通过进程间通信,使进程之间产生联系,而线程几乎没有独立性,因为在进程的不同线程共享地址空间,但是线程也有自己私有的一部分数据:

PCB控制块
线程ID
一组寄存器

errno
信号屏蔽字
调度优先级

在这些里边,我们要清楚记得,线程的PCB控制块,上下文数据,栈空间是独立的。
进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

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

进程和线程有以下的关系:
在这里插入图片描述
可能一个进程中只有一个线程,也可能有多个线程,进程数:线程数=1:n。

三、线程的优点

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

由于创建进程的成本是非常高的,成本分为时间和空间,一个线程只需创建一个PCB,但是创建进程必须创建页表,进程地址空间等。

=与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多

进程之前的切换,会切换进程的PCB,地址空间,页表,上下文数据,而线程只需要切换PCB,上下文数据即可,因为进程中的线程共用着同一个地址空间,必然使用同一个页表。

线程占用的资源要比进程少很多

线程只占用进程中的一部分资源,这部分资源是由进程来分配的。

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

当有多个处理器时,一个进程中,每个PCB都可以被CPU调度,然后运行,此时将进程的任务分配给线程之后,每个线程只去完成自己的一部分任务即可。

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

当要进行I/O操作时,并且I/O比较慢时,可以让一个PCB等待,而其他的线程去执行其他的任务。

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

计算密集型,例如解压压缩包,需要进行大量的计算,将任务分配给各个线程,就会提高效率。

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

例如我们在线观看电视剧,电影时,有多个线程,就可以将等待I/O的时间重叠,例如在多个线程同时等待,就可以提高效率。

四、线程的缺点

性能损失

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

通常情况下,在计算密集型线程应比处理器的数量少,如果多于处理器的数量,CPU在调度线程时会过度切换,所以说线程也并不是越多越好。

健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。
由于多线程程序中,多个线程同时共享地址空间,所以某个线程会干扰其他线程,比如如果一个线程崩溃,进程就会崩溃,其他的线程自然而然也会崩溃。

缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
共享地址空间,所以可能其他线程可以访问该线程的数据。

编程难度提高

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

五、线程异常

单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出。
使用pthread_create接口来创建线程,详细讲解见下篇文章
在这里插入图片描述
接下来先编写一个多线程的程序:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#define NUM 5

void* pthread_run(void* args)
{
   while(1){
     int num = *(int*)args;
        printf("我是新线程[%d], 我创建的线程ID是: %lu\n", num,pthread_self());
        sleep(2);
        if(num==3)
        {
          printf("thread number : %d quit\n", num);
          //野指针,会造成线程崩溃
          int* p = NULL;
          *p=100;
        }
  }
}
int main()
{
  pthread_t tid[NUM];
  for(int i=0;i<NUM;i++ )
  {
    pthread_create(&tid[i],NULL,pthread_run,(void*)&i);
    sleep(1);
  }

 while(1)
 {
     printf("我是主线程, 我的thread ID: %lu\n", pthread_self());

     printf("#########################begin########################\n");
     for(int i = 0; i < NUM; ++i){
         printf("我创建的线程[%d]是: %lu\n", i, tid[i]);
     }
     printf("#########################end########################\n");
     sleep(1);
 }

  return 0;
}

当运行一段时间之后,因为野指针,说明线程一定会崩溃,那么整个进程呢?
在这里插入图片描述
在这里插入图片描述
我们发现整个进程都崩溃了,这就是线程的异常会引起进程的异常。

六、线程用途

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

例如,当我们下载视频软件时,使用多线程就能实现边下载边观看,就是在一个线程执行下载任务时,另外一个线程执行播放任务。


下一篇文章进入线程的控制章节。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux】线程详解之线程概念 的相关文章

  • 在 execl 在输出中不可见之前打印

    include
  • Linux shell 根据第二列对文件进行排序?

    我有一个这样的文件 FirstName FamilyName Address PhoneNumber 如何按 FamilyName 排序 如果这是 UNIX sort k 2 file txt 您可以使用多个 k用于对多列进行排序的标志 例
  • linux新手关于嵌入式linux设备驱动的问题

    最近在研究linux驱动 正如我读过的那些文章所说 设备驱动程序模块很可能会根据内核的需要自动加载 因此我想知道内核如何确定为特定设备 声卡 I2C spi 设备 等 我也无法彻底想象内核如何在启动时检测每个硬件设备 与嵌入式linux相关
  • Xvfb 冻结初始化 GLX 扩展

    我正在尝试运行无头 Xvfb 服务器来捕获 Amazon EC2 micro 上的屏幕截图 但它在 GLX 上陷入了困境 我使用此脚本安装了 GLX Xvfb 和所有库 https gist github com joekiller 414
  • 如何通过 makefile 在 Linux 上安装程序? [复制]

    这个问题在这里已经有答案了 可能的重复 Linux Unix make install 应该包含什么 https stackoverflow com questions 528399 what should linux unix make
  • 如何在Linux上用C/C++编写Web服务器[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在考虑在 Linux 平台上开发一个小型 阅读 初级 Web 服务器 但我不知道从哪里开始 我希望它能够做的是 监听特定端口 接受
  • 任何退出 bash 脚本但不退出终端的方法

    当我使用exitshell 脚本中的命令 该脚本将终止终端 提示符 有什么方法可以终止脚本然后停留在终端中吗 我的剧本run sh预计通过直接获取或从另一个脚本获取来执行 编辑 更具体地说 有两个脚本run2 sh as run sh ec
  • 在ubuntu中打开spyder

    我想在ubuntu中打开spyder Python IDE 通常我会在 shell 中编写 spyder 它会打开spyder IDE 现在 当我在shell中编写spyder时 它只是换行 什么也没有发生 类似于按 enter 我如何找回
  • 链接错误:命令行中缺少 DSO

    我对 Linux 使用 Ubuntu 14 04 LTS 64 位 相当陌生 来自 Windows 并且正在尝试移植我现有的 CUDA 项目 当通过链接时 usr local cuda bin nvcc arch compute 30 co
  • 如何在 Linux 和 C 中使用文件作为互斥体?

    我有不同的进程同时访问 Linux 中的命名管道 并且我想让此访问互斥 我知道可以使用放置在共享内存区域中的互斥体来实现这一点 但作为一种家庭作业 我有一些限制 于是 我想到的是对文件使用锁定原语来实现互斥 我做了一些尝试 但无法使其发挥作
  • “git add”返回“致命:外部存储库”错误

    我刚刚进入 git 的奇妙世界 我必须提交我对程序所做的一系列更改 位于名为的目录中 var www myapp 我创建了一个新目录 home mylogin gitclone 从这个目录中 我做了一个git clone针对公共回购 我能够
  • LINUX:如何锁定内存中进程的页面

    我有一个 LINUX 服务器 运行一个具有大量内存占用的进程 某种数据库引擎 该进程分配的内存太大 需要将其中一部分换出 换出 我想做的是将所有其他进程 或正在运行的进程的子集 的内存页面锁定在内存中 以便只有数据库进程的页面被换出 例如
  • Linux无法删除文件

    当我找到文件时 我在删除它们时遇到问题 任务 必须找到带有空格的文件并将其删除 我的尝试 rm find L root grep i 但我有错误 rm cannot remove root test No such file or dire
  • 来自守护程序的错误响应:加入会话密钥环:创建会话密钥:超出磁盘配额

    我尝试在我的服务器上安装 docker 使用本教程 https docs docker com install linux docker ce ubuntu 我想远程运行 docker 镜像并使用 portainer Web 界面来管理一切
  • 如何在 Linux 上通过 FTP 递归下载文件夹 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • 如何才能将 TCP 连接返回到同一端口?

    机器是 RHEL 5 3 内核 2 6 18 有时我在 netstat 中注意到我的应用程序有连接 建立了 TCP 连接本地地址 and 国外地址是一样的 其他人也报告了同样的问题 症状与链接中描述的相同 客户端连接到本地运行的服务器的端口
  • ioctl 命令的用户权限检查

    我正在实现 char 驱动程序 Linux 并且我的驱动程序中有某些 IOCTL 命令仅需要由 ADMIN 执行 我的问题是如何在 ioctl 命令实现下检查用户权限并限制非特权用户访问 IOCTL 您可以使用bool capable in
  • 批量删除文件名中包含 BASH 中特殊字符的子字符串

    我的目录中有一个文件列表 opencv calib3d so2410 so opencv contrib so2410 so opencv core so2410 so opencv features2d so2410 so opencv
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • 执行命令而不将其保留在历史记录中[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在进行软件开发时 经常需要在命令行命令中包含机密信息 典型示例是将项目部署到服务器的凭据设置为环境变量 当我不想将某些命令存储在命令历史记

随机推荐

  • Spring源码阅读-getBean逻辑分析记录

    getBean 从缓存中获取Bean Object sharedInstance getSingleton beanName 上述代码会从三个map中读取缓存的Bean 这三个map也是俗称的 this singletonObjects 一
  • ip2region的使用,来自csdn的回答

    使用Go语言使用ip2region库的例子如下 导入ip2region包 import github com lionsoul2014 ip2region binding golang ip2region 加载ip2region的数据库文件
  • JDK1.8函数式接口Function、Consumer、Predicate、Supplier

    JDK1 8函数式接口Function Consumer Predicate Supplier 1 函数式接口定义 函数式接口 Functional Interface 有且仅有一个抽象方法的接口 但可以有多个非抽象方法的接口 函数式接口
  • c++ 中map 的find 用法

    用find函数来定位数据出现位置 它返回的一个迭代器 当数据出现时 它返回数据所在位置的迭代器 如果map中没有要查找的数据 它返回的迭代器等于end函数返回的迭代器 程序演示 include
  • java.lang.String cannot be cast to [Ljava.lang.Object;错误的原因及解决办法

    错误信息 java lang ClassCastException java lang String cannot be cast to Ljava lang Object at com six biz impl ReportBizImpl
  • 认识网络、几种常用的网络拓扑图

    交换协议 VLAN技术 虚拟局域网 STP技术 生成树协议 VRRP技术 虚拟路由冗余协议 VPN 虚拟专用网络 名词解释 路由协议 http HTTPS tcp ip 静态路由配置 OSPF协议 RIP协议 ACL访问控制 什么是网络 简
  • 【100天精通python】Day38:GUI界面编程_PyQt 从入门到实战(中)_数据库操作与多线程编程

    目录 专栏导读 4 数据库操作 4 1 连接数据库 4 2 执行 SQL 查询和更新 4 3 使用模型和视图显示数据 5 多线程编程 5 1 多线程编程的概念和优势 5 2 在 PyQt 中使用多线程 5 3 处理多线程间的同步和通信问题
  • 论文带读——3D Neural Field Generation using Triplane Diffusion

    论文带读 3D Neural Field Generation using Triplane Diffusion YssssMikey Tips 我会基本上几天更新一篇论文引读 一般是AIGC模型 3D Diffusion方向每日在Arxi
  • JDBC的实现(IDEA版)

    前期准备 开发环境 IDEA 2021 1 3 JAVA 1 8 MYSQL 8 0 32 msql用户名 root 密码 123 下载MySQL JDBC 驱动 前往MySQL官网下载对应版本的MySQL Connector J驱动 下载
  • pix2pix gan_用python构建pix2pix gan

    pix2pix gan There are times that we want to to transform an image into another style Let s say we have a fine collection
  • 基于WOA-SVM算法的乳腺肿瘤识别算法的MATLAB仿真

    基于WOA SVM算法的乳腺肿瘤识别算法的MATLAB仿真 随着医疗技术的发展 计算机在医学影像领域中的应用越来越广泛 乳腺肿瘤是女性常见的一种肿瘤 准确地进行乳腺肿瘤检测和诊断对女性健康至关重要 本文将介绍一种基于WOA SVM算法的乳腺
  • centos下git相关操作以及部分问题解决方案

    主要记录两件事情 一个是如何git clone github代码到本地 二是git clone到非空文件夹下出错的解决方案 第一 在电脑没有安装git的情况下 手动安装git 具体步骤如下 1 安装依赖的包 yum install curl
  • c++使用curl库发送https请求

    一 环境win7 64位 vs2010 二 文件准备 2 1文件下载 libcurl 下载页面 http curl haxx se download html 我下载的是https curl haxx se download curl 7
  • angular项目打包发布流程

    1 从git更新代码 运行测试看有没有错误 测试ie兼容性 2 修改配置文件并编译打包代码 修改连接服务器的配置文件 双击 3 拷贝文件到服务器 xshell连接到linux 命令 pwd 查看当然文件目录 ll 列出该文件下所有的文件列表
  • Visual Studio 2019解决右侧工具栏消失

    项目场景 准备打开Visual Studio 2019却发现右侧的工具栏消失了 问题描述 新建项目后发现右侧的解决方案资源管理器消失了 不便于添加源文件书写代码 如图 原因分析 可能是以前在操作中将项目移除或删除等等将窗口删掉了 解决方案
  • 用jquery实现简单的表单验证效果

    看了 锋利的jquery 一书 练习了下期中的一个用jquery写表单验证的例子 效果如图 总结 这是个比较简单的表单验证 主要验证了表单中的用户名和邮箱两个必填选项 表单验证其实质是个不断往下过滤的过程 主要思路
  • selenium自动化录入数据

    将csv或者txt里的数据通过selenium自动录入到网页系统里 输入一个数据操作完后自动输入下一个数据 依次遍历所有的数据 比如百度搜索 有十个词要搜索 输入第一个词搜出结果后再接着输入第二个继续搜 依次遍历十个 求大神赐教 给个思路或
  • 21天打卡挑战学习MySQL——《SQL基础入门》第二周 第四篇

    活动地址 CSDN21天学习挑战赛 一 什么是SQL MySQL是一个关系型数据库管理系统 前世 瑞典MySQLAB公司 今生 属于Oracle旗下产品 MySQL是最好的RDBMS Relational Database Manageme
  • Unity游戏界面点击深色模式,游戏会退出问题的解决方法

    问题 在Unity游戏接入到android平台上时 经常会遇到这样的问题 游戏玩着玩着 点击深色模式 游戏会突然退出 具体情形下图所示 一 点击深色模式游戏退出 二 正常情况 三 解决方法 在AndroidManifest xml里 对继承
  • 【Linux】线程详解之线程概念

    前言 在我们的教材中 对线程给出以下的概念 是进程内部的一个执行分支 在进程的内部运行 属于进程的一部分 比进程更加轻量化 可能有的人看完之后都是懵的 什么叫在进程的内部运行 什么又是执行分支 为什么比进程轻量化 我们就带着这三个问题 重新