《Linux从练气到飞升》No.25 Linux中多线程概念

news2024/11/24 6:30:00

🕺作者: 主页

我的专栏
C语言从0到1
探秘C++
数据结构从0到1
探秘Linux
菜鸟刷题集

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢阅读!!!

文章目录

    • 前言
    • 线程的基本概念
      • Linux中的线程
      • Linux线程与进程区别
      • 进程和线程的关系
      • Linux线程和接口的认识
      • 线程的数据
        • 线程的私有数据
        • 线程的共有数据
      • 看看猪跑
    • 线程的优缺点(了解)
      • 线程的优点
      • 线程的缺点
        • 线程异常
    • 线程用途

前言

本篇主要介绍一下线程相关的知识~

线程的基本概念

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

理解:
一个进程对应着的线程应该>=1,它至少要含有一个线程才能维持进程的存在,所谓的更加轻量化指的是每个线程都享有进程内的一定的资源,并负责各自的任务,相对来说就更加精细化和轻量化,所以说在内核视角中线程是CPU调度的基本单位,承担进程资源的一部分基本实体。
毫无疑问,在操作系统中存在大量的进程,现在我们知道,一个进程对应着至少一个线程,那么可以推断在操作系统中会存在更多的线程,既如此操作系统为了管理它就会想办法将它们组织起来,之前将进程的时候讲过,操作系统管理的法则是“先描述,再组织”,进程是用一个叫PCB的结构体来描述的,线程是用一个叫TCB的结构体来描述的,在windows操作系统中就是这样管理线程的,不过在Linux中则使用了一种巧妙的方法来管理。

Linux中的线程

之前在进程部分我们讲过 进程 = 程序 + PCB + mm_struct + 页表和mmu + 物理地址,Linux在创造线程概念的时候并没有像上面我们所推断的一样创造TCB结构体来管理每一个线程 而是复用了进程的PCB结构体,如下图。
image.png
这些线程的task_struct和进程task_struct共享同一个进程地址空间,每个线程都会使用其中部分代码和数据,但是CPU并不管这些,它只管执行就好,这样的优点是操作系统只需要将“精力”专注于线程间的资源分配就好了。

Linux线程与进程区别

我们在创建进程的时候通常会为进程创建一个独立的程序地址空间来保证它的独立性而线程则恰恰相反它们只创建PCB共用一个进程地址空间。
但是同样的进程间为了通信或者是其他目的也会选择性的共用一块公共资源而线程为了保证自己能够正确运行也会有一些相对其他线程独立的资源。
主要区别如下:

  • 进程具有独立性 但是一部分资源是可以共享的(管道 ipc等)
  • 线程大部分资源是共享的 但是一部分资源是私有的 (PCB 栈 上下文等)

进程和线程的关系

如果我们把国家比作一个操作系统 那么国家中的每个家庭就是一个进程。每个家庭之间是相互独立的,不可能说今天另外一个家庭的人不经过你的同意就住进你家里。
但是家庭与家庭之间也需要通信,可能周末会邀请关系好的邻居上你家客厅做客。
家庭中的每个人就可以看作是线程,在这个家里大部分的资源是共享的,但是每个人也有自己的隐私,所以说一部分资源是私有的。

Linux线程和接口的认识

在Linux中线程是用进程模拟实现的,所以说Linux中不会给我们提供线程的操作接口 (这里解释下 其实Linux不是没有能力去提供这些操作接口 而是它想要保持一个相对自由的状态给用户) ,而是给我们提供了一个在同一个进程地址空间中创建PCB的方法 ,分配给资源指定的PCB。
但是作为一个用户来说 使用这种方法的学习成本太高了 我们更需要一个完整的线程库
所以说一些应用级的开发工程师就在应用层对于轻量级的Linux接口进行封装成为了我们经常使用的原生线程库pthread库。

线程的数据

线程的数据分为私有的数据和共有的数据,在同一个进程就决定了多个线程的全部数据不会都是私有的,而在同一个进程的多个线程就决定了必然有共有的部分。

线程的私有数据
  • 线程ID 这个很好理解 因为我们要使用线程ID来区分每个线程
  • 一组寄存器 这组寄存器用来保存线程的上下文信息
  • 栈 每个线程都有临时的数据需要压栈 如果不区分那数据就全乱了
  • 信号屏蔽字
  • 调度优先级
线程的共有数据

因为多个线程是在同一个进程地址空间中 所以说进程地址空间的代码段和数据段都是共享的

  • 如果定义一个函数 在各线程中都可以调用
  • 如果定义一个全局变量 在各线程中都可以访问到

除此之外 各线程还共享以下进程资源和环境

  • 文件描述符表 (进程打开一个文件后其他线程也能够看到)
  • 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
  • 当前工作目录(cwd)
  • 用户ID和组ID等等

看看猪跑

前面讲了这么多,接下来我们先创建一个线程,然后让它跑一跑看看。
再写代码之前还要介绍一个创建线程的函数,它也是pthread库中的。
它就是pthread_create函数

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
返回值:
	线程创建成功返回0 失败返回错误码
	这里值得注意的是在线程库中 几乎所有的返回值都是成功返回0 失败返回错误码
参数说明:
	thread:获取创建成功的线程ID 该参数是一个输出型参数
	attr: 用于设置创建线程的属性 如果我们传入NULL则设置为默认属性
	start_routine:这是一个函数地址 传入我们想要这个线程执行的函数
	arg: 传给线程例程的参数 (默认是void* 类型 记得类型强转不然会报警告)

下面是猪跑 : )
makefile

mycode:mycode.cc
	g++ -o $@ $^ -l pthread

.PHONY:clean

clean:
	rm -f mycode

需要注意的是,有些机器上面不加-l pthread在运行的时候会报错,这是因为找不到库文件所导致的。
mycode.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

void* run_thread(void* args)
{
    char* msg = (char*)args;
    while(1)
    {
        printf("I'm a thread my msg is:%s\n" , msg);
        sleep(1);
    }
}


int main()
{
    pthread_t tid;
    pthread_create(&tid ,NULL ,run_thread ,(void*)"thread 1");
    while(1)
    {
        printf("I'm main thread\n");
        sleep(1);
    }
    return 0;
}

上面代码的意思是我们创建一个子线程 这个线程不停的打印参数发送过去的消息 同时我们的主进程不停的打印另外的信息
最后的结果如下:
image.png
我们可以看到两个循环在同时进行!!
以前可从来没有见过这样的情况!!
使用ps -aL查看轻量级进程
image.png
我们可以看到多了两个进程但是他们的PID是一样的,但是它们的LWP却不同
其实在操作系统调度的时候看的就是LWP
但是之间学进程的时候说操作系统调度的时候看的是PID
难道说错了?
实际上都是对的,在当时的语境下,我们只学过单进程执行流,此时进程就只对应着一个线程,此时的PID等于LWP,所以怎么说也没问题。
但是在现在学了线程以后,我们就要注意看的什么情况下了。

线程的优缺点(了解)

线程的优点

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

计算密集型 执行流的大部分任务 主要以计算为主 比如加密解密 大数据查找等
IO密集型 执行流的大部分任务 主要以IO为主 比如刷磁盘 访问数据库 访问网络等

线程的缺点

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

如果单个线程出现异常 比如说出现除零错误等 有可能会导致整个进程崩溃
造成这样的原因是 操作系统发送信号是向进程发送的

线程用途

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

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

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

相关文章

WIN11如何固定文件夹查看方式

找一个文件夹&#xff0c;设置成自己需要的视图方式 文件夹选项>查看>应用到文件夹 缺点&#xff1a;所有相同类型文件夹都会使用此视图

什么是IPA,和RPA有啥区别和联系?

∵ IPA中包含了RPA的“PA”&#xff0c;AI的“I” ∴IPARPAAI&#xff0c;等式成立&#xff01; AI&#xff1a;或人工智能&#xff0c;是一种复杂的计算机技术&#xff0c;旨在模仿人类智能行为和决策的能力。它涵盖了多种技术和方法&#xff0c;包括&#xff1a;机器学习&am…

脑洞大开、超级新奇小说,情节绝对出乎你的意料,不能错过

今天小郑要向大家推荐三本令人眼前一亮的小说&#xff0c;这些作品不仅脑洞大开&#xff0c;而且文笔也绝对一流&#xff0c;绝对不容错过&#xff01; 《明尊》 但是&#xff0c;这部小说也有一些缺点。尤其是在不同副本之间质量起伏不定&#xff0c;有时候作者为了突出主角…

9.Vue前端使用iframe集成帆软报表的单点登录

一、背景 需要把帆软报表内嵌到若依里面来。 二、帆软设置 2.1 帆软报表的url 打开帆软后端里面的【目录管理】查看具体报表的url 帆软报表的具体地址为: Frm聚合报表地址: 【帆软的服务http】+【/webroot/decision/view/form?viewlet=demo/demo.frm】 CPT普通报表的地…

什么是配电室电能监测系统?

为了保证电力系统的安全、稳定、经济运行成为了当务之急。配电室电能监测系统作为一种新兴技术&#xff0c;有效提高了配电室的运行管理水平&#xff0c;降低了电力系统的风险。接下来&#xff0c;小编来为大家介绍下配电室电能监测系统&#xff0c;一起来看下吧&#xff01; 一…

Python 框架学习 Django篇 (八) 代码优化、数据库冗余处理

我们开发软件系统的时候&#xff0c;需要不断的反思我们代码里面是否有可以优化的地方。而优化的重点之一&#xff0c;就是把冗余的代码优化为可以复用的库。我们在前面编写了一些功能&#xff0c;但是其中存在很多冗余的方法 mgr/medicine.py mgr/k8s.py mgr/medicine.py 打开…

postman连接mysql报ETIMEDOUT错误解决方法

问题 在cmd中执行xmysql -h localhost -u username -p password -d database命令后,报errorno: ETIMEDOUT’超时错误; 解决方法 给执行命令加上端口信息 -o post: xmysql -h localhost -u username -p password -d database -o port

企业采用生成式人工智能需要考虑什么

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 最近&#xff0c;各行业采用人工智能生成内容&#xff08;AIGC&#xff09;的趋势显着。这种变革性技术的一些著名实施包括Notion AI…

分别使用Java和C语言实现猜数字游戏(数字随机生成)

目录 一、Java实现 1.内容介绍 2.思路 3.完整代码 二、C语言实现 1.思路 2.完整代码 三、总结 1.产生随机数 2.分支结构 一、Java实现 1.内容介绍 &#xff08;1&#xff09;在程序运行起来之后&#xff0c;就提醒我们输入数字&#xff0c;猜的数字控制在[0-100]&a…

从用户角度出发,探索低代码服务商选择本地部署模式的内在逻辑

随着越来越多的企业开始关注本地部署模式&#xff0c;很多低代码服务商也将视角转向了本地部署模式。毕竟只有将各种软件和程序部署在本地&#xff0c;才能够更好地保护企业的数据安全。但是&#xff0c;选择恰当的本地部署模式&#xff0c;对于服务商来说是一个非常复杂的过程…

8.OsgEarth 鼠标位置及LabelControl中文显示

愿你出走半生,归来仍是少年&#xff01; 在人机交互中&#xff0c;最常用的就是鼠标。获取鼠标在三维场景中的空间位置是保证交互结果正确的保障。 1.LabelControl 文本标签控件&#xff0c;可方便的添加在场景顶层。 设置编码及字体可正确的显示出中文。 setFont(osgText::re…

android studio app红叉无法编译

1.起源 今天前台小姐姐穿了一个白色的超短裙,和小姐姐聊了聊人生梦想,聊生活趣事,回到工位你马....报了一个这错误,无法运行了,明天就要打包测试了,顿时菊花一紧,急了一头汗,这你马咋回事,看了旁边的产品肥仔,迷着小眼露出了银建的笑容.开始排雷.... 意思就是说gradle初始化失…

如何使用 NFTScan NFT API 在 BNB Chain 网络上开发 Web3 应用

BNB Chain 是一条以太坊虚拟机兼容的区块链&#xff0c;是加密资产行业顶尖项目的测试和前沿探索。通过引入权益权威证明&#xff08;PoSA&#xff09;共识机制&#xff0c;BNB Chain 创建了验证一个允许节点、代币持有者、开发者和用户都能够从区块链中获益的生态系统&#xf…

Sentinel 哨兵数据 更新下载地址 2023年11月

1. 欧空局官方下载 2023年11月开始&#xff0c;原来欧空局的下载地址和应用有了变化&#xff0c;现在迁移到以下新地址下载&#xff1a; https://dataspace.copernicus.eu/ 我这边测试需要重新注册用户才能进行登录和使用&#xff0c;界面使用和之前差不多&#xff0c;具体操作…

如何在校园跑腿系统小程序中构建稳健的订单处理与分配系统?

1. 数据库设计 首先&#xff0c;设计订单数据结构。使用数据库&#xff08;例如MySQL、MongoDB等&#xff09;&#xff0c;创建订单表以存储订单相关信息&#xff0c;包括订单ID、用户信息、交付地址、订单状态等。 CREATE TABLE orders (order_id INT AUTO_INCREMENT PRIMAR…

掌握口才与演讲技巧,让你职场中脱颖而出

在职场竞争日趋激烈的今天&#xff0c;口才和演讲能力已经成为一个人成功的重要标志之一。掌握了优秀的口才与演讲技巧&#xff0c;不仅可以帮助你在工作中更好地表达自己和传达信息&#xff0c;同时也可以让你在同事和上级心中留下深刻印象&#xff0c;从而在职场中脱颖而出&a…

突发,50亿美元芯片订单被取消? | 百能云芯

11月2日消息&#xff0c;据华尔街日报&#xff0c;美国新推出的出口管制规定可能迫使AI芯片巨头英伟达取消明年数十亿美元的对华先进制程芯片订单&#xff0c;此举可能令中国科技公司无法获得关键的AI资源。 据知情人士透露&#xff0c;此前&#xff0c;英伟达今年对中国的先进…

.NET桌面程序如何设置任务栏图标右键菜单中的名称

右键任务栏中应用程序图标时会显示程序名称&#xff0c;例如&#xff1a; 这里显示的并不是程序文件名DingTalk&#xff0c;而是文件属性中详细信息选显卡下的“文件说明”。 在.NET桌面程序中&#xff0c;是通过修改程序集名称&#xff08;AssemblyTitle&#xff09;来设置…

2024年天津医科大学临床医学院专升本招生对口专业限制专科目录

2024年天津医科大学临床医学院高职升本科招生对口专业目录 药学&#xff1a; 药学 护理&#xff1a; 护理、助产 公共事业管理&#xff1a; 医药卫生大类&#xff1a;护理、助产、临床医学、口腔医学、中医学、中医骨伤、针灸推拿、蒙医学、藏医学、维医学、傣医学、哈医学…

sso简单记录

首先我们再次复习一下&#xff0c;多个系统之间为什么无法同步登录状态&#xff1f; 前端的Token无法在多个系统下共享。后端的Session无法在多个系统间共享。 关于第二点&#xff0c;我们已在 "SSO模式一" 章节中阐述&#xff0c;使用 Alone独立Redis插件 做到权限…