当前位置: 首页 > article >正文

Linux之多线程概念

目录

线程概念 

线程共享的资源

线程独有的资源 

线程优点

线程缺点 


在之前,我们已经学习了进程相关的知识点,如进程的基本概念和基本操作,本期我们将开始进行线程的学习,探索线程和进程的关系。

线程概念 

在学习线程之前,我们先来回顾一下进程的相关概念。图示如下。

 上图为进程的内核结构,运行可执行程序时,可执行程序的代码和数据被加载到内存之后,操作系统生成了进程相关的数据结构,如进程控制块(task_struct),进程地址空间(mm_struct)和页表,我们把进程相关的数据结构和加载到内存中的代码的数据统称为进程,CPU通过调度进程去运行从物理内存中映射到地址空间的代码,最终进程完成了可执行程序的执行。

但是线程和进程又有什么关系呢? 

其实,可以这样理解,线程就是进程内部的一个执行流,之前我们认识的进程我们一直以为这个进程就只有一个执行流,但是在今天以及以后,我们在谈论进程时,我们一般默认认为进程内部有多个执行流。通过图示为大家展示。

以往的学习,我们认为进程内部就只有一个执行流也就以为只有一个pcb,但是实际上,一个进程内部可以有多个执行流,可以拥有多个pcb,一个pcb其实就是一个线程,多个pcb整体称为一个进程。所以我们也称线程为轻量级进程。 

通过线程,我们可以将代码进行分割,以往一个pcb执行的代码此时由多个pcb进行执行,可以大大的提升代码执行的效率。

由上图可以看出,所有的pcb都是共享一个进程地址空间的,那么是不是可以理解为进程中所有的资源都是共享的呢?当然不是,线程大部分的资源都是共享的,少部分的资源是独有的。

线程共享的资源

纵使线程内部有着很多的线程,但是这些线程本质上都是继承了主线程的pcb,所以也继承了父进程中相关的数据,如struct files_struct*指指针。线程共享的资源有四种。

  • 文件描述符表。因为所有的线程其实本质上都是基于主线程产生的,继承了主线程的数据。所以所有线程共享同一文件描述符表。
  • 信号的处理方式,因为信号是给进程发的,信号的处理是以进程为单位的,所以与线程是无关的,即每个线程对信号的处理方式都是相同的。
  • 当前的工作目录。
  • 用户id和组id。

线程独有的资源 

线程再运行时,一定会产生自己的临时数据,这些临时数据是存储在栈中的,而且每个线程的调度时间都是根据时间片进行调度的,所以一定有自己的上下文数据。

  • 线程id。
  • 栈。
  • 一组寄存器,用于存放上下文数据。 
  • 调度的优先级,每个线程的调度的先后是不同的。

在Linux中一定会存在大量的线程,既然存在大量的线程,操作系统一定会对线程进行管理,按照以往的方式,应该是先描述,后组织,但是Linux操作系统的做法是,Linux并不会为线程创建专门的结构体进行描述和管理,而是会复用进程的结构体去创建线程,从而去复用进程的相关接口,所以可以理解为线程其实就是进程的复用。但是同时Linux操作系统同时为用户提供了原生线程库(第三方库pthread),供用户对线程进行相应的操作。怎么验证,线程是复用进程的呢?通过一段代码为大家解释。

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


void* thread_run(void* args)
{
  const char* name=(const char*)args;
  while(1)
  {
    printf("我是%s线程\n",name);
    sleep(1);
  }

}

int main()
{
  pthread_t tid;
  pthread_create(&tid,NULL,thread_run,(void*)"thread 1 ");
  while(1)
  {
    printf("我是主线程\n");
    sleep(1);
  }

  return 0;
}

 运行结果如下。运行是因为是使用了第三方库,所以要在编译时添加-pthread选项。

使用ps -aL可以查看正在运行的线程。

在代码中有两个线程,一个主线程,一个使我们创建的线程,我们发现这两个线程的pid是相同的也意味着,这两个线程同属与一个进程,但是其LWP是不同的,LWP可以理解为线程的id,且CPU在调度时是以LWP为最小单位进行调度的。也即CPU在调度是是以线程为基本单位进行调度的。

此时我们可以给出线程的概念。

进程是参与系统资源分配的基本单位,线程是CPU调度的基本单位。线程在进程的地址空间中运行。

线程优点

  • 线程创建的代价比进程小很多,因为线程的创建只需创建对应的pcb一个数据结构体即可,只参与进程地址空间中资源的分配;而进程的创建要创建大量的结构体,task_struct,mm_struct,页表,除此之外,还要维护进程地址空间和物理内存的映射关系,相当复杂。
  • 线程占用的资源比进程少很多,因为进程的资源是被线程分配的。
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现,提升计算效率。计算密集型应用主要是加密和大数据运算等,主要使用CPU资源。
  • I/O密集型应用,为了提高性能,将I/O等待操作重叠。线程可以同时等待不同的I/O操作。I/O密集型应用主要是网络云盘,在线下载,看电影等等,主要使用内存和外设的I/O资源。

线程缺点 

  • 性能损失。在计算密集型应用中,当线程的数量大于CPU数量时,会导致CPU调度线程时来回切换,线程的来回切换也是需要消耗资源的,所以会造成计算机性能的损失。
  • 健壮性降低。当一个线程发生异常时,操作系统发现异常会向对应的进程发送信号,导致进程异常退出,进程异常退出,所有的线程也就异常退出了。
  • 缺乏访问控制。因为在进程内部,线程数量较多时,无法确保有效的访问某一个进程。
  • 编程难度提高。多线程的代码的编写和调试难度极高。

 以上便是线程概念的相关内容,本期内容到此结束^_^


http://www.kler.cn/a/290220.html

相关文章:

  • 使用elementUI实现表格行拖拽改变顺序,无需引入外部库
  • mongoDB的安装及使用
  • Flink_DataStreamAPI_输出算子Sink
  • 常用的Anaconda Prompt命令行指令
  • ODOO学习笔记(8):模块化架构的优势
  • 【Hadoop实训】Hive 数据操作①
  • mongodb在Java中条件分组聚合查询并且分页(时间戳,按日期分组,年月日...)
  • OpenCV绘图函数(11)计算文本字符串在特定字体、尺寸和厚度下的大小的函数getTextSize()的使用
  • 模型从 HuggingFace 转存到 ModelScope
  • 【ubuntu使用笔记】Ubuntu Desktop 访问SMB共享文件夹
  • Spring声明式事务使用详情(知识点+案例)
  • 【Java】封装
  • 《Zookeeper 的监听机制及原理解析》
  • 后台使用Motionbuilder
  • 聚类算法-Kmeans聚类
  • 【60天备战软考高级系统架构设计师——第八天:设计模式概述】
  • Spring Boot项目中结合MyBatis详细使用
  • “智能化自动化” 架构之4:中间建模脑的软件设计三大原则-依赖倒置控制反转和依赖注入
  • 在react中利用three.js 渲染模型 让鼠标拖拽是模型转动
  • redhat7.9安装zsh以及常用插件
  • 具有平面规则性的单目视觉惯性里程计
  • 反射API与AOP在微服务治理中的实践与思考
  • 飞利浦开放式耳机怎么样?南卡、飞利浦、QCY耳机真实测评
  • 【Leetcode 2399 】 检查相同字母间的距离 —— 哈希表
  • git分支的管理
  • Windows 欺骗主机 Burn-In 的自动化工具