【Hello Linux】线程概念

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

作者:@小萌新
专栏:@Linux
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:简单介绍linux中的多线程

线程基本概念

一般在书上我们会这么介绍一个线程

线程是进程内部的一个执行流 他是进程的一部分 粒度要比进程更加细和轻量化

那么我们应该怎么理解呢? 下面是我的梳理思路

首先线程是进程的一个执行流的对吧 那么一个进程中是不是可能有很多的线程呢? 答案当然是肯定的

那么我们就可以推断 系统中一定存在着大量的线程

既然系统中存在着大量的线程 操作系统作为管理者就要想办法将这些线程管理起来

而根据我们管理的法则:先描述 再组织 操作系统会描述这些线程并且将它们进行组织(默认双链表)

那么操作系统要怎么描述这些线程呢? 答案和进程类似 用一个叫做TCB的结构体来描述

在windows操作系统中 操作系统管理线程就是按照我们上面的逻辑进行的

不过在我们的Linux系统中使用了一种更加巧妙的方法

Linux中的线程

之前在进程部分我们讲过 进程 = 程序 + PCB + mm_struct + 页表和mmu + 物理地址 如下图所示

【Hello Linux】线程概念

Linux在创造线程概念的时候并没有像上面我们所推断的一样创造TCB结构体来管理每一个线程 而是复用了进程的PCB结构体

【Hello Linux】线程概念

这些线程的PCB和进程PCB共享一个进程地址空间 它们每个线程都会分走一点代码和数据

在cpu看来此时的PCB是要小于等于我们之前讲解的PCB概念的

可是cpu不关心这些 它认为一个PCB就是一个执行流 它只管执行就好

这里我们就能得出一个重要的结论

Linux中没有为线程专门设计TCB 而是使用进程PCB模拟线程

这样子设计的优点是什么呢?

最直观的优点 我们不必去设计线程TCB了 这代表着我们节省了大量时间去设计数据结构和算法

与此同时 操作系统也只需要聚焦在线程间的资源分配上就好了

进程线程再理解

我们在博客的开篇就提到过了书上有这么一个概念

线程是进程内部的一个执行流 他是进程的一部分 粒度要比进程更加细和轻量化

我们应该怎么理解上面的这句话

  • 内部: 表示线程在进程的虚拟地址空间中
  • 执行流:CPU在调度的时候只看PCB 所以说PCB中曾经指定的方法和数据CPU都可以直接的调度

那么为什么线程是进程的一部分呢? 要回答这个问题 我们需要再深入了解下进程

进程 = 程序 + PCB + mm_struct + 页表和mmu + 物理地址

【Hello Linux】线程概念

在我们之前的学习过程中 进程默认是只有一个执行流的

而在今天的学习之后 进程是可能会有多个执行流的

我们要明确一点 创建进程的代价是非常大的 这里的代价包括时间+空间

  • 时间: cpu处理并创建PCB进程地址空间等资源的时间
  • 空间:创建的PCB和进程地址空间等占用的空间

所以说在内核视角中 进程是承担分配系统资源的基本实体

而线程只需要创建一个PCB和获取一点进程的资源所以说在内核视角中线程是CPU调度的基本单位 承担进程资源的一部分基本实体

Linux线程和接口的认识

在Linux中线程是用进程模拟实现的 所以说Linux中不会给我们提供线程的操作接口 (这里解释下 其实Linux不是没有能力去提供这些操作接口 而是它想要保持一个相对自由的状态给用户) 而是给我们提供了一个在同一个进程地址空间中创建PCB的方法 分配给资源指定的PCB

但是作为一个用户来说 使用这种方法的学习成本太高了 我们更需要一个完整的线程库

所以说一些应用级的开发工程师就在应用层对于轻量级的Linux接口进行封装成为了我们经常使用的原生线程库

Linux线程与进程区别

我们在创建进程的时候通常会为进程创建一个独立的程序地址空间来保证它的独立性而线程则恰恰相反它们只创建PCB共用一个进程地址空间

但是同样的进程间为了通信或者是其他目的也会选择性的共用一块公共资源而线程为了保证自己能够正确运行也会有一些独立的资源

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

线程私有的数据

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

线程公有的数据

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

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

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

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

进程和线程的关系

如果我们把国家比作一个操作系统 那么国家中的每个家庭就是一个进程

每个家庭之间是相互独立的 不可能说今天另外一个家庭的人不经过你的同意就住进你家里

但是家庭与家庭之间也需要通信 可能周末会邀请关系好的邻居上你家客厅做客

家庭中的每个人就可以看作是线程 在这个家里大部分的资源是共享的

但是每个人也有自己的隐私 所以说一部分资源是私有的

代码验证

我们可以通过下面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* 类型 记得类型强转不然会报警告)

下面是代码示例

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <pthread.h>
  4 #include <unistd.h>
  5 
  6 void* run_thread(void* args)
  7 {
  8   char* msg = (char*)args;
  9   while(1)
 10   {
 11     printf("im a thread my msg is:%s\n" , msg);
 12     sleep(1);
 13   }
 14 }
 15 
 16 
 17 int main()
 18 {
 19   pthread_t tid;
 20   pthread_create(&tid ,NULL ,run_thread ,(void*)"thread 1");
 21   while(1)
 22   {
 23     printf("im main thread\n");
 24     sleep(1);
 25   }
 26   return 0;
 27 } 

上面代码的意思是我们创建一个子线程 这个线程不停的打印参数发送过去的消息 同时我们的主进程不停的打印另外的信息
【Hello Linux】线程概念

但是这里我们发现我们进行编译之后会出现这样子的情况 这是因为我们找不到库文件所导致的

具体的原因可以参考我动静态库这篇博客

动静态库

所以说我们想要编译成功这个文件需要先指令连接的库文件

【Hello Linux】线程概念
演示效果如下

【Hello Linux】线程概念

我们发现这里竟然有两个while循环在同时执行 这在我们以前单执行流的时候是不想象的

当这两个进程在运行的时候我们可以使用下面的指令来查看轻量级进程

ps -aL

【Hello Linux】线程概念

我们可以看到这里两个进程的PID都是一样的 但是他们的LWP却不同

所以这里我们就能很简单的推断出

操作系统调度的时候查看的是LWP

但是我们之前在进程部分讲过 操作系统调度的时候看的是进程PID 这句话错了吗?

实际上这句话放在我们之前的条件下是没错的 因为我们当时是单进程执行流 此时的进程PID就等于LWP 所以那么说也对

线程的优缺点

线程的优点

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

概念说明

计算密集型 执行流的大部分任务 主要以计算为主 比如加密解密 大数据查找等

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

线程的缺点

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

线程异常

如果单个线程出现异常 比如说出现除零错误等 有可能会导致整个进程崩溃

造成这样子的原因是 操作系统发送信号是向进程发送的文章来源地址https://www.toymoban.com/news/detail-408598.html

线程用途

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

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

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

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

相关文章

  • 【Linux】多线程1——线程概念与线程控制

    📝 个人主页 :超人不会飞) 📑 本文收录专栏 :《Linux》 💭 如果本文对您有帮助,不妨 点赞、收藏、关注 支持博主,我们一起进步,共同成长! 💭理解线程需要和进程的概念紧密联系。 线程是一个执行分支,执行粒度比进程更细,调度成本更低; 进程是分配系统资源的

    2024年02月12日
    浏览(28)
  • 【Linux】多线程 --- 线程概念 控制 封装

    从前种种,譬如昨日死。从后种种,往如今日生。 1.1 进程资源如何进行分配呢?(地址空间+页表) 1. 首先我们来看一个现象,当只有第一行代码时,编译是能通过的,但会报warning,当加了第二行代码时,编译无法通过,报error。 第一行代码能编过的原因是权限缩小,虽然

    2024年02月03日
    浏览(63)
  • Linux之多线程(上)——Linux下的线程概念

    本文介绍了地址空间和二级页表、Linux下的线程、线程的优缺点以及线程与进程的关系等概念。 地址空间是进程能看到的资源窗口 :一个进程可以看到代码区、堆栈区、共享区、内核区等,大部分的资源是在地址空间上看到的。 页表决定进程真正有用资源的情况 :进程认为

    2024年02月09日
    浏览(43)
  • 【Linux学习】多线程——页表详解 | 线程概念 | 线程理解

    🐱作者:一只大喵咪1201 🐱专栏:《Linux学习》 🔥格言: 你只管努力,剩下的交给时间! 我们在之前一直都提到页表,知道它的作用是将虚拟地址映射到物理地址,但是它具体怎么映射的,它的结构是什么样的,并没有提及过。 上诉代码,会在运行时报错,原因是str指向

    2024年02月05日
    浏览(40)
  • Linux线程概念

    目录 一、页表详解 1.地址的属性 2.页框 3.页表录和页表项 二、认识线程 1.线程的概念 2.轻量级进程 三、线程的简单控制 1.线程的创建 2.PID和LWP 3.线程异常 4.线程的资源 (1)共享的资源 (2)独有的资源 5.线程的特点 我们虽然已经知道了页表可以储存虚拟地址和物理地址的

    2024年02月11日
    浏览(38)
  • 【Linux】线程概念

           🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️林 子       🛰️博客专栏:✈️ Linux       🛰️社区 :✈️ 进步学堂       🛰️欢迎关注:👍点赞🙌收藏✍️留言 我们都知道, 进程是操作系分配资源的基本实体。

    2024年02月08日
    浏览(60)
  • Linux之线程概念

    目录 一、细粒度划分 1、堆区细粒度划分 2、物理内存和可执行程序细粒度划分 3、虚拟地址到物理地址的转化 二、线程的概念 1、基本概念 2、线程的优点 3、线程的缺点 4、线程异常  5、线程用途 三、Linux下的进程和线程 在语言中,我们知道,用户自己申请的空间是存在于

    2024年03月10日
    浏览(39)
  • 初识linux之线程基本概念

    目录 一、进程地址空间和页表再理解 二、线程 1.线程的概念 2. 进程与线程 3. 线程的意义 4.线程的优点缺点 4.1 优点 4.2 缺点  4.linux中线程的优缺点 4.1 优点 4.2 缺点 5. linux中线程创建相关接口 5.1 线程创建 6. 通过代码查看进程与线程的关系 6.1 线程库 6.2 信号与线程 6.3 主线程

    2023年04月12日
    浏览(41)
  • 【Linux】多线程概念初讲

    线程大章节第一篇文章 文章目录 前言 一、linux线程基本概念 二、线程与进程的对比       1.线程控制的接口 总结 什么是线程呢? 在一个程序里的一个执行路线就叫做线程( thread )。更准确的定义是:线程是 “ 一个进程内部的控制序列”。 一切进程至少都有一个执行线

    2024年02月08日
    浏览(40)
  • 【Linux】多线程概念再理解

    物理内存的宽度为1字节 如使用c语言,可以定义出char类型(1字节),在虚拟地址空间上可以把1字节的单位映射到内存中 如果认为内存是按照字节为单位去划分的,实际上是不正确的 把数据从磁盘换入物理内存,把数据从物理内存换入磁盘,是一个高频的工作,物理磁盘是一个

    2024年02月05日
    浏览(57)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包