【Linux】线程、线程控制、地址空间布局

头像
⭐️个人主页:@小羊
⭐️所属专栏:Linux
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 1、Linux线程
    • 1.1 线程的优缺点
    • 1.2 线程异常和用途
    • 1.3 线程等待
    • 1.3 线程终止
    • 1.4 线程分离
    • 1.5 线程ID和地址空间布局
    • 1.6 线程栈


1、Linux线程

  • 进程是一个执行起来的程序,进程 = 内核数据结构 + 代码和数据。进程是承担分配系统资源的实体。
  • 线程是执行流,执行粒度比进程更细,是进程内部的一个执行分支。线程是OS调度的基本单位。

进程是承担分配系统资源的基本实体,线程不参与分配,只需要划分进程的资源就可。新线程和主线程谁先运行,是不确定的。线程创建出来,要对进程的时间片进程瓜分。
也就是说进程执行的任务还要被细分成几份给更小的线程去执行,可以想象到线程除了执行粒度比进程更细之外大致相似,也就是说OS也要像管理进程一样管理线程,如果用像管理进程一样的方法管理线程,那么就太复杂了。

Linux执行流,统一称为轻量级进程(LWP)Linux中没有真正意义上的线程,Linux线程概念使用LWP模拟实现。

在这里插入图片描述

//新线程
void *run(void *args)
{
   while (true)
   {
       cout << "new thread, pid : " << getpid() << endl;
       sleep(1);
   }
   return nullptr;
}

int main()
{
   cout << "I am a process, pid : " << getpid() << endl;
   pthread_t tid;
   pthread_create(&tid, nullptr, run, (void*)"thread_1");

   //主线程
   while (true)
   {
       cout << "main thread, pid : " << getpid() << endl;
       sleep(1);
   }
   return 0;
}

在这里插入图片描述
在这里插入图片描述

虚拟内存可以将不连续的物理内存通过映射转化为连续的。当我们讨论虚拟地址到物理地址转换的时候,页表的映射关系已经在加载的时候关联好了。虚拟地址到物理地址转换的过程,是硬件(MMU)自动完成的。

:》如何理解进程划分资源给线程,如何做到?需要刻意做吗?
线程执行不同的入口函数,就拥有了这个函数的地址,资源自然而然就被划分好了。

虚拟地址和物理地址如何转换:

在这里插入图片描述

页表可以看作一个简单的数组,前20位用来映射物理地址,后12位作为标记位。

:》所以我们怎么知道当前内存是否被使用呢?
通过页表的映射我们可以得到页框的起始地址,在用起始地址除以4KB,就得到了管理物理内存数组的下标,通过下标也就找到了管理这个内存的信息。

缺页中断:当程序代码量大时只加载部分代码,执行完这部分代码后再往后执行就会在页表的标记位(是否命中)中发现错误,CPU出错触发软中断,发送信号,OS对这个信号的处理就是加载剩余代码,这个过程就是缺页中断。


1.1 线程的优缺点

| 线程优点:

  1. 创建一个线程的代价比创建一个进程的代价小的多。

  2. 与进程之间的切换相比,线程之间的切换需要OS做的工作要少很多。

    • 最主要的区别是线程的切换虚拟内存空间依然是不变的,而进程切换会改变,这两种切换都是操作系统内核完成的,最显著的消耗是需要将寄存器中的内容切换。
    • 另一个显著的消耗就是上下文的切换会扰乱处理器的缓存机制,当改变虚拟内存空间的时候,处理的页表缓冲TLB(快表)(缓存高频的虚拟到物理的映射)和cache(缓存代码和数据块)也会被全部刷新。
  3. 线程占用的资源比进程少。

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

  5. 在等待慢速IO操作结束的同时,程序可执行其他的计算任务。

  6. 将计算分解到多个线程中实现,还可以同事等待不同的IO操作。

| 线程缺点:

  1. 如果线程数量过多会有调度的性能损失。
  2. 健壮性降低,线程之间是缺乏保护的。
  3. 缺乏访问控制,在一个线程中调用某些OS函数会对整个进程造成影响。

1.2 线程异常和用途

  • 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃。

  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出。

  • 合理的使用多线程,能提高CPU密集型程序的执行效率。

  • 合理的使用多线程,能提高IO密集型程序的用户体验。


1.3 线程等待

| 为什么需要线程等待?

  • 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
  • 创建新的线程不会复用刚才退出线程的地址空间。

在这里插入图片描述

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的:

  1. 如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_cancel异常终止,retval所指向的单元里存放的是常数PTHREAD_CANCELED
  3. 如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
  4. 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

1.3 线程终止

如果需要只终止某个线程而不是终止整个进程,有三种方法:

  1. 线程调用return退出。
  2. 线程调用pthread_exit退出。
  3. 线程调用pthread_cancel取消线程。

任何地方调用exit,表示进程退出。

取消线程,一定是目标线程已经启动了,join得到的返回值是-1。

需要注意pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。


1.4 线程分离

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
  • 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。

在这里插入图片描述

主线程可以不等待新线程,将目标线程设置为分离状态。线程可以被分离,也可以自己分离。

| 线程被等待的状态:

  1. joined:线程需要被join(默认)
  2. detach:线程分离(主线程不需要等待新线程)

注意:在多执行流情况下,主执行流是最后退出的。

在这里插入图片描述

这里执行5秒后join失败,进程退出,所以线程分离后就不能join了。

线程不能直接进行程序替换,因为其他部分代码可能正在被其他线程执行,但是可以在线程内部创建子进程,进行程序替换


1.5 线程ID和地址空间布局

pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事。

在这里插入图片描述

  • 线程属性在线程库中维护,就是TCB,线程ID就是线程库中属性在地址空间中的地址。
  • 主线程的栈只有一个,其他线程的栈是在共享区中被动态申请出来的。

在这里插入图片描述

线程局部存储只能修饰内置类型。


1.6 线程栈

虽然Linux将线程和进程不加区分的统一到了task_struct,但是对待其地址空间的stack还是有些区别的。

  • 对于Linux进程或者说主线程,简单理解就是main函数的栈空间,在fork的时候,实际上就是复制了父亲的stack空间地址,然后写时拷贝(cow)以及动态增长。如果扩充超出该上限,则栈溢出会报段错误(发送段错误信号给该进程)。进程栈是唯一可以访问未映射页而不一定会发生段错误⸺超出扩充上限才报。
  • 对于主线程创建的子线程而言,其stack不再是向下生长的,而是事先固定下来的,线程栈一般是调用glibcpthread库接口pthread_create共享区创建的。也就是说这种栈一旦用尽就没了,这是和创建进程的fork不同的地方。
  • 对于子线程的stack,它其实是在进程的地址空间中map出来的一块内存区域,原则上是线程私有的,但是同一个进程的所有线程生成的时候,是会浅拷贝生成者的task_struct的很多字段,如果愿意,其它线程也还是可以访问到。

使用容器管理多线程:

#include "Thread.hpp"
#include <unordered_map>
#include <memory>

#define NUM 10
using thread_ptr_t = std::shared_ptr<ThreadModule::Thread>;

//创建多线程
int main()
{
    std::unordered_map<std::string, thread_ptr_t> threads;
    for (int i = 0; i < NUM; i++)
    {
        thread_ptr_t t = std::make_shared<ThreadModule::Thread>([](){
            while (true)
            {
                std::cout << "hello world" << std::endl;
                sleep(1);
            }
        });
        threads[t->Name()] = t;
    }

    for (auto &thread : threads)
    {
        thread.second->Start();
    }

    for (auto &thread : threads)
    {
        thread.second->Join();
    }
    return 0;
}

本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言操作符(详细讲解)

目录 前言 一、算术操作符 一元操作符&#xff1a; 二元操作符&#xff1a; 二、赋值操作符 代码例子&#xff1a; 三、比较操作符 相等与不相等比较操作符&#xff1a; 大于和小于比较操作符&#xff1a; 大于等于和小于等于比较操作符&#xff1a; 四、逻辑操作符 逻辑与&…

宏_wps_宏修改word中所有excel表格的格式_设置字体对齐格式_删除空行等

需求&#xff1a; 将word中所有excel表格的格式进行统一化&#xff0c;修改其中的数字类型为“宋体&#xff0c; 五号&#xff0c;右对齐&#xff0c; 不加粗&#xff0c;不倾斜”&#xff0c;其中的中文为“宋体&#xff0c; 五号&#xff0c; 不加粗&#xff0c;不倾斜” 数…

第一届“启航杯”网络安全挑战赛WP

misc PvzHE 去这个文件夹 有一张图片 QHCTF{300cef31-68d9-4b72-b49d-a7802da481a5} QHCTF For Year 2025 攻防世界有一样的 080714212829302316092230 对应Q 以此类推 QHCTF{FUN} 请找出拍摄地所在位置 柳城 顺丰 forensics win01 这个软件 云沙盒分析一下 md5 ad4…

GESP2024年3月认证C++六级( 第三部分编程题(2)好斗的牛)

参考程序&#xff08;暴力枚举&#xff09; #include <iostream> #include <vector> #include <algorithm> using namespace std; int N; vector<int> a, b; int ans 1e9; int main() {cin >> N;a.resize(N);b.resize(N);for (int i 0; i &l…

QFramework实现原理 一 :日志篇

作为一款轻量级开源的Unity程序框架&#xff0c;QFramework结合了作者凉鞋多年的开发经验&#xff0c;是比较值得想要学习框架的初学者窥探一二的对象&#xff0c;我就尝试结合凉鞋大大给出的文档和ai&#xff0c;解析一下其背后的代码逻辑&#xff0c;以作提升自己的一次试炼 …

图论汇总1

1.图论理论基础 图的基本概念 二维坐标中&#xff0c;两点可以连成线&#xff0c;多个点连成的线就构成了图。 当然图也可以就一个节点&#xff0c;甚至没有节点&#xff08;空图&#xff09; 图的种类 整体上一般分为 有向图 和 无向图。 有向图是指 图中边是有方向的&a…

_CLASSDEF在C++中的用法详解及示例

_CLASSDEF在C++中的用法详解及示例 _CLASSDEF的定义与使用示例说明代码解析总结在C++编程中,宏(Macro)是一种预处理指令,它允许程序员在编译之前对代码进行文本替换。_CLASSDEF是一个自定义的宏,它提供了一种便捷的方式来定义类及其相关类型。本文将详细介绍_CLASSDEF在C+…

华为数据之道-读书笔记

内容简介 关键字 数字化生产 已经成为普遍的商业模式&#xff0c;其本质是以数据为处理对象&#xff0c;以ICT平台为生产工具&#xff0c;以软件为载体&#xff0c;以服务为目的的生产过程。 信息与通信技术平台&#xff08;Information and Communication Technology Platf…

从CRUD到高级功能:EF Core在.NET Core中全面应用(四)

初识表达式树 表达式树&#xff1a;是一种可以描述代码结构的数据结构&#xff0c;它由一个节点组成&#xff0c;节点表示代码中的操作、方法调用或条件表达式等&#xff0c;它将代码中的表达式转换成一个树形结构&#xff0c;每个节点代表了代码中的操作例如&#xff0c;如果…

系统思考—问题分析

很多中小企业都在面对转型的难题&#xff1a;市场变化快&#xff0c;资源有限&#xff0c;团队协作不畅……这些问题似乎总是困扰着我们。就像最近和一位企业主交流时&#xff0c;他提到&#xff1a;“我们团队每天都很忙&#xff0c;但效率始终没见提升&#xff0c;感觉像是在…

MySQL 的索引类型【图文并茂】

基本分类 文本生成MindMap:https://app.pollyoyo.com/planttext <style> mindmapDiagram {node {BackgroundColor yellow}:depth(0) {BackGroundColor SkyBlue}:depth(1) {BackGroundColor lightGreen} } </style> * MySQL 索引** 数据结构角度 *** B树索引*** 哈…

华硕笔记本装win10哪个版本好用分析_华硕笔记本装win10专业版图文教程

华硕笔记本装win10哪个版本好用&#xff1f;华硕笔记本还是建议安装win10专业版。Win分为多个版本&#xff0c;其中家庭版&#xff08;Home&#xff09;和专业版&#xff08;Pro&#xff09;是用户选择最多的两个版本。win10专业版在功能以及安全性方面有着明显的优势&#xff…

【深度学习】 自动微分

自动微分 正如上节所说&#xff0c;求导是几乎所有深度学习优化算法的关键步骤。 虽然求导的计算很简单&#xff0c;只需要一些基本的微积分。 但对于复杂的模型&#xff0c;手工进行更新是一件很痛苦的事情&#xff08;而且经常容易出错&#xff09;。 深度学习框架通过自动…

虚幻浏览器插件 UE与JS通信

温馨提示&#xff1a;本节内容需要结合插件Content下的2_Communication和Resources下的sample.html 一起阅读。 1. UE调用JS 1.1 JS脚本实现 该部分共两步: 导入jstote.js脚本实现响应函数并保存到 ue.interface 中 jsfunc 通过json对象传递参数&#xff0c;仅支持函数名小…

CDN、源站与边缘网络

什么是“源站” 源服务器 源服务器的目的是处理和响应来自互联网客户端的传入请求。源服务器的概念通常与边缘服务器或缓存服务器的概念结合使用。源服务器的核心是一台运行一个或多个程序的计算机&#xff0c;这些程序旨在侦听和处理传入的客户端请求。源服务器可以承担为网…

数据库、数据仓库、数据湖有什么不同

数据库、数据仓库和数据湖是三种不同的数据存储和管理技术&#xff0c;它们在用途、设计目标、数据处理方式以及适用场景上存在显著差异。以下将从多个角度详细说明它们之间的区别&#xff1a; 1. 数据结构与存储方式 数据库&#xff1a; 数据库主要用于存储结构化的数据&…

Java Swing 基础组件详解 [论文投稿-第四届智能系统、通信与计算机网络]

大会官网&#xff1a;www.icisccn.net Java Swing 是一个功能强大的 GUI 工具包&#xff0c;提供了丰富的组件库用于构建跨平台的桌面应用程序。本文将详细讲解 Swing 的基础组件&#xff0c;包括其作用、使用方法以及示例代码&#xff0c;帮助你快速掌握 Swing 的核心知识。 一…

Mac m1,m2,m3芯片使用nvm安装node14报错

使用nvm安装了node 12/16/18都没有问题&#xff0c;到14就报错了。第一次看到这个报错有点懵&#xff0c;查询资料发现是Mac芯片的问题。 Issue上提供了两个方案&#xff1a; 1、为了在arm64的Mac上安装node 14&#xff0c;需要使用Rosseta&#xff0c;可以通过以下命令安装 …

多模态论文笔记——ViViT

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细解读多模态论文《ViViT: A Video Vision Transformer》&#xff0c;2021由google 提出用于视频处理的视觉 Transformer 模型&#xff0c;在视频多模态领域有…

网络安全 | F5-Attack Signatures-Set详解

关注&#xff1a;CodingTechWork 创建和分配攻击签名集 可以通过两种方式创建攻击签名集&#xff1a;使用过滤器或手动选择要包含的签名。  基于过滤器的签名集仅基于在签名过滤器中定义的标准。基于过滤器的签名集的优点在于&#xff0c;可以专注于定义用户感兴趣的攻击签名…