【Linux】:线程概念

embedded/2024/10/22 8:02:46/

朋友们、伙计们,我们又见面了,本期来给大家带来线程概念相关代码和知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

​ 

目录

​编辑​ 

1. 线程的概念

2. 线程的理解

3. 线程的优缺点 

4. 重谈地址空间

4.1 虚拟地址的转化 

5.5 进程和线程


1. 线程的概念

关于线程有两种概念:

  • 线程是比进程更加轻量化的一种执行流 / 线程是进程内部执行的一种执行流;
  • 线程是CPU调度的基本单位 / 进程是承担系统资源的基本实体。

那么为什么要有线程呢?

我们创建进程就是要让它执行我们的代码,但是进程的创建到运行这个阶段需要做很多事情(从磁盘加载可执行、由虚拟到物理的转化等等),如果我们只是想单纯的运行代码,那么有很多个可执行需要运行的话,通过创建进程的方式来运行就有点太麻烦了,所以需要有一种比进程更加轻量化的去执行我们的代码。

因为地址空间是进程的“资源窗口”,所以进程可以这个窗口来进行资源的获取,所以为了减少成本,只创建PCB,然后指向同一个虚拟地址空间,实现共享,简单的理解就是将虚拟地址空间中的代码区、数据区、堆栈区进行划分为多个小块,此时多个PCB指向虚拟地址空间只参与资源的分配任务。

那么既然有线程,OS也需要对这些线程进行管理,那么怎么管理呢?先描述、再组织,如果重新设置一套对于线程的管理方法那么实在太麻烦了,线程和进程很相似,所以直接采用管理进程的那一套方案即可,直接复用。

2. 线程的理解

CPU是调度执行流来运行的,那么在了解完线程之后,CPU获取到一个执行流大小是小于等于进程。这该怎么理解呢?我们如何看待现在的进程呢?内部包含多个执行流的进程!

进程 = 内核数据结构 + 代码和数据,现在所说的进程就是包含进程PCB、虚拟地址空间、页表、代码和数据。

其中不只包含一个执行流,而是有多个执行流(在一个地址空间有多个PCB)。

我们之前看待进程其中里面只有一个执行流,所以CPU在调度的时候,如果调度的进程只有一个执行流,那么就是进程,如果有多个执行流,那么就调度其中一个执行流,就叫做线程,所以CPU在调度执行流的大小总是小于等于进程! 

所以线程是CPU调度的基本单位,而进程是承担系统资源的基本实体。

所以创建线程只需要创建PCB,所以线程也叫做轻量级进程。

所以可以得出:

  • 1. 线程的创建相比进程更加简单;
  • 2. 线程在进程的地址空间中运行。

接下来我们通过代码的方式先直观的看一下线程,其中关于线程控制的代码会专门解释,先观察代码运行结果:

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>// 新线程
void *ThreadRoutine(void *arg)
{const char *threadname = (const char *)arg;while (true){std::cout << "I am a new thread: " << threadname << ", pid: " << getpid() << std::endl;sleep(1);}
}int main()
{pthread_t tid;// 创建线程pthread_create(&tid, nullptr, ThreadRoutine, (void *)"thread 1");// 主线程while (true){std::cout << "I am main thread" << ", pid: " << getpid() << std::endl;sleep(1);}return 0;
}

这段代码首先会创建一个新的线程,然后一个执行流去执行新线程的代码,紧接着往下走就是主线程的代码,代码结果就是会有两个循环在一直执行:

使用指令 ps -aL可以查看线程

可以看出线程的调度区分并不是用PID来区分,而是LWP,并且主线程的LWP和PID一样。

3. 线程的优缺点 

优点:

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

缺点:

  • 健壮性降低,多线程在运行时,各个线程之间不相互独立,一个线程的异常很有可能导致其它线程出现异常,换句话说线程之间是缺乏保护的
  • 缺乏访问控制,在一个线程中调用某些OS函数有可能会对整个进程造成影响
  • 调试难度比较高,多线程程序比单线程程序调试更为复杂

4. 重谈地址空间

我们的可执行程序被编译好之后以ELF的格式存储在磁盘上,当要执行时会先加载的内存,在之前文件系统部分了解到文件系统IO的基本单位大小是4KB,即使我们所要修改的数据只有1比特位,也需要一次性加载4KB,所以为了统一和方便,将物理内存以4KB划分为多个小块,每一个块被叫做一个页框,磁盘文件中的文件以4KB分为多个小块,每一块被叫做一个页帧,这样子每一次加载磁盘文件时,就根据4KB很容易的将数据加载进来。

以32位4GB的机器来计算,页框的数量有10万多个页框,所以OS也需要将这些页框给管理起来,所以就需要先描述再组织,为页框构建描述结构体的对象(包含页框的属性、使用情况、标志位等等),然后用数组将这些结构体管理,对页框的管理就变成了对数组的增删查改。

4.1 虚拟地址的转化 

通过上面对物理内存以4KB进行划分,所以虚拟地址到物理地址的转化不只只通过页表来转化,虚拟到物理的转化其实是在CPU内部转化的,在我们的CPU中的eip寄存器保存的是虚拟地址,当CPU拿到一个虚拟地址时会通过MMU从虚拟到物理的转化:

例如:虚拟地址32个比特位

1111 1111 1110 0000 0000 0000 0000 0001 

  • 前10个比特位可以找到对应的页目录;
  • 次10个比特位可以找到页表,通过页表可以找到页框;
  • 页框起始地址 + 低12个比特位可以找到页内偏移;

通过整个的虚拟地址就可以访问到物理地址上的数据内容。

可以看到其实划分页表的本质就是划分地址空间。

5.5 进程和线程

进程是资源分配的基本单位
线程是调度的基本单位
线程共享进程数据,但也拥有自己的一部分数据:
  • 线程ID
  • 一组寄存器
  • errno
  • 信号屏蔽字
  • 调度优先级

简单的每个线程都有自己独立的硬件上下文数据与栈结构。

线程还共享以下进程资源和环境:

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

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!   


http://www.ppmy.cn/embedded/129509.html

相关文章

【计算机网络】localhost,127.0.0.1 和 0.0.0.0傻傻分不清?这篇文章带你认识

一句话总结&#xff0c;127.0.0.1 用于本地测试&#xff0c;只能由本机访问&#xff0c;localhost 是映射到127.0.0.1 的域名&#xff1b;而 0.0.0.0 用于使服务对所有网络接口可见&#xff0c;可以被其他计算机访问。 关系解释 127.0.0.1 这是一个特殊的IP地址&#xff0c;…

java List<Map<String, Object>> 转 List<JSONObject> 的几种方式

目录 方法一&#xff1a;使用传统循环 方法二&#xff1a;使用 Java 8 的流&#xff08;Stream&#xff09;API 方法三&#xff1a;使用 Guava 库 总结 将 List<Map<String, Object>> 转换为 List<JSONObject> 有多种方法。以下是几种常见的方法&#xf…

Docker设置日志滚动

问题描述 Docker 容器中的进程会将打印到控制台(console)的日志保存到容器的目录下&#xff0c;默认的 Docker 配置不带有日志的回滚。会在自己的容器目录下往同一个日志文件中不停写入&#xff0c;最后会导致磁盘空间占满的问题。 解决方案 方案一&#xff1a;全局范围内修…

时间数据可视化基础实验——Python实现

【实验名称】 实验一:时间数据的可视化 【实验目的】 1.掌握时间数据在大数据中的应用 2.掌握时间数据可视化图表表示 3. 利用python程序实现堆叠柱形图的可视化 【实验原理】

Web前端-JavaScript输入输出语法

一、输出语法 1.语法一 作用:向body内输出内容 注意:如果输出的内容写的是标签&#xff0c;也会被解析成网页元素 例如&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewpor…

大数据-172 Elasticsearch 索引操作 与 IK 分词器 自定义停用词 Nginx 服务

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

ORB -SLAM2 ---- Tracking::Tracking和GrabImageStereo

文章目录 一、Tracking::Tracking1. 函数讲解&#xff0c;2. 函数源码 一、GrabImageStereo()1. 函数讲解2. 函数源码 三、 学习方法&#xff08;路线&#xff09;四、总结 一、Tracking::Tracking 1. 函数讲解&#xff0c; 这是Tracking中的构造函数&#xff0c;此函数的主要…

一起搭WPF架构之livechart的MVVM使用介绍

一起搭WPF架构之livechart使用介绍 前言ModelViewModelView界面设计界面后端 效果总结 前言 简单的架构搭建已经快接近尾声了&#xff0c;考虑设计使用图表的形式将SQLite数据库中的数据展示出来。前期已经介绍了livechart的安装&#xff0c;今天就详细介绍一下livechart的使用…