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

Linux:线程概念、理解、控制

目录

一、认识线程

1.认识线程V1

2.认识线程V2

3.认识线程V3

4.认识线程V4

5.认识线程V5

二、线程控制

1.前言

2.创建线程

3.线程等待

4.线程终止

5.线程分离

三、线程理解


一、认识线程

1.认识线程V1

        借用大多数计算机教材的话,线程是进程的一个执行分支,线程是CPU调度的基本单位。

        多进程的缺点在于,每创建一个进程,就要创建一个PCB对象,一份地址空间,一张页表,想办法把这部分消耗缩小,就只需新建一份"PCB",地址空间和页表共用一份,代码部分再均分,比如有5个进程就把所有调度函数均分为5份,如此一来,CPU并不知道自己是执行多进程,只是在调度一个又一个PCB,而用户看来,CPU却是通过“多线程的方式”提高了效率。

2.认识线程V2

        既然如此,多个进程有多个线程,系统中存在大量线程,必然需要描述、组织,然而,Linux下,并没有再单独定义线程结构体,而是用进程的结构体来模拟线程。

3.认识线程V3

  • 重新认识进程

        以前认识进程,这个进程是单执行流,用现在的话说就是内部只有一个线程。

        现在认识进程,这个进程内部有多个线程,多个执行分支。

        总结的看,进程是系统分配资源的单位,而线程是系统调度的单位,因此,往后理解进程,都要站在系统分配资源的角度去看。

4.认识线程V4

  • cpu调度角度

        现在来看,有的进程只有一个执行流,cpu调度可以称为调度进程,而有的进程有多个执行流,cpu调度时称为调度线程。

        Linux下,为了统一这种含糊不清的概念,把cpu调度的执行流统称为轻量级进程。线程<= 执行流 <= 进程。因此,cpu不再区分自己到底是在线程调度还是进程调度,都称为执行流。

  • 内核级虚拟机技术

        我们现在看待进程,它是操作系统分配资源的基本单位,可以认为是一个容器,那么如果一个进程所对应的代码部分是一个操作系统,意味着这个操作系统支持内核级虚拟机技术。

5.认识线程V5

  • 页表

        抛出一个问题,操作系统是怎么给多线程均分代码的?

        第一个结论,内存本质上是有限个4KB的内存块,定义为数组,方便增删查改。

        第二个结论,页表并不是简单的K-V映射,虚拟地址是有划分的,比如32位的虚拟地址,前10位是一个整体,中间10位是一个整体,后12位一般是页内偏移地址,而页表其实是多张页目录和多张页内偏移表。

        第三个结论,多线程划分代码,其实就是让每一个线程拿到自己代码所在的n张页内偏移表。

二、线程控制

1.前言

        ps -aL指令查看LWP(light weight process)

ps -aL

        过去,要么是单进程单执行流,要么是多进程多执行流,而学习多线程后,变成了单进程多执行流。

        在内核层面,cpu调度的是一个又一个的LWP,只有轻量级进程。

        Linux的内核代码没有线程结构体,只有轻量级进程的结构体定义。而在用户层面,要严格区分进程和线程。因此需要对内核的系统调用封装,于是有一个库叫 pthread库,这个库不属于内核代码,但是安装Linux操作系统时必须安装这个库。

2.创建线程

        pthread_create

        通过man手册可以得知,pthread_create这个函数用来创建一个新的线程,使用这个函数需要包含头文件<pthread.h>,由于在3号手册查到了这个函数,因此说明这个函数不是系统调用,是用户层封装的函数。此外,man手册提示编译和链接时要加特定选项-pthread

void* HandleTask(void* args)
{//新线程std::string threadname = (char*)args;
}   int main()
{//主线程pthread_t tid;pthread_create(&tid,nullptr,HandleTask,nullptr);return 0;
}

3.线程等待

        在学习进程时,父进程要等待回收子进程。而线程这快,主线程也要等待新线程。

  • 运行成功的多线程程序,主线程一定是最后运行结束的。主线程退出=进程退出,如果主线程的主体代码运行完毕,而新线程还在运行,则主线程需要等待新线程的执行结果。

        pthread_join

        第二个参数是输出型参数。 

void* HandleTask(void* args)
{//新线程std::string threadname = (char*)args;int cnt =5;while(cnt){sleep(1);cnt--;}return (void*)111;
}   int main()
{//主线程//创建pthread_t tid;pthread_create(&tid,nullptr,HandleTask,(void*)"name");//等待void* ret = nullptr;int cnt =10;while(cnt){sleep(1);cnt--;}int abc = pthread_join(tid,&ret);std::cout << "abc->" << abc << "new thread ret->" << (long)ret << std::endl;return 0;
}

        没有发生异常的情况下,新线程的运行结果是可以通过参数手动获取到的。 如果任何一个线程出现异常(div 0, 野指针),都会导致整个进程退出! 同时说明多线程代码往往健壮性不好。

4.线程终止

  • 线程return
  • pthread_exit

        哪一个线程调用这个函数,哪一个线程就被终止。

pthread_exit((void*)111);
  • pthread_cancel

        这个函数由主线程调用,用来发送终止信号。 

 //终止测试sleep(1);pthread_cancel(tid);

        返回结果为-1,表明不是正常退出。

5.线程分离

        pthread_detach

         

        新线程做线程分离

pthread_detach(pthread_self());

        主线程也可以主动分离掉新线程。

pthread_detach(tid);

  • 线程分离后,到底发生了什么?什么样的情况需要线程分离?

        每一个新线程默认是需要让主线程等待的,即主线程需要调用pthread_join函数。如果主线程不需要关心新线程的执行状态,那么就可以将这个新线程分离。新线程分离后,仍旧和其他线程共享资源,并且保留自己原来的私有资源但是!如果主线程调用pthread_join去等待这个新线程,是会出错的,即被分离的线程意味着不再需要主线程等待。不管怎么设计程序,都建议让主线程最后一个退出。

三、线程理解

  • 多线程相比多进程的优点 

 创建一个新线程的开销要比一个新进程小得多。

与进程的切换相比,线程切换时操作系统所做的操作要少得多。

1.切换线程时,需要切换上下文的寄存器相对少一点,切换线程,只需切换保存是哪一个线程的寄存器,而切换进程,还要多切换用来保持虚拟地址空间、页表的寄存器。

2.由于cpu缓存技术, 加载内存中代码时是一次性加载多行,而切换进程时,前后的代码内容更大概率不是在相邻存储,更大概率可能要刷新缓存,而多线程共享代码,大概率不需要刷新缓存。

  • 线程私有的数据

1.线程的硬件上下文数据,本质是cpu寄存器的值,(这部分数据调度线程)

2.每一个线程都有自己的独立栈结构,(用来保证线程的常规运行)

  • 线程共享的数据

1.代码部分、全局数据

2.文件描述符表、页表、进程地址空间等等

  • C++11的多线程

语言层的多线程,其实是对pthread库的进一步封装。

  • 更深的理解pthread_t

        如何标识一个唯一的线程,Linux下有这样两种设计,在内核一层,即操作系统层面,并没有定义线程结构体,而是定义了一个LWP结构体,名为轻量级进程,等同于线程,内核里面LWP是唯一的。但是,Linux内核对线程的各种操作控制并不同于我们理论上学习的线程操作控制,因此,Linux又做封装,即封装好的pthread库,编译链接多线程程序时,必须要链接这个库,本质是第三方库,因为它既不属于语言,也不属于操作系统调用。

        pthread_t就是pthread库里面定义的概念。

        加载动态库,加载到物理内存后,经页表映射到虚拟地址空间中的共享区,在代码区中执行到pthread_t tid这行代码后,cpu则跳转到共享区(动态库已经加载)对应的定义处执行这行代码。

        pthread动态库对线程做了管理,即定义了线程结构体,也使用数据结构控制。

         

        每一个线程都有对应的结构体,这个结构体有的地方也叫tcb而结构体的起始地址,就是pthread_t tid的值。

        上文提到了线程私有的数据之一,就是独立栈结构。也是在pthread库里面的线程结构体中定义的,因为每一个线程都有对应执行的代码,可能会创建局部变量,这些变量就保存在这部分栈结构中。

        线程局部存储:全局变量归所有线程共有,如果希望只写一份定义全局变量的代码,但是实际上却是多个进程各有一份数据,就可以用像下面这样定义,这些值保存在线程局部存储空间中。

 __thread int IngTime = 0;

相关文章:

Linux:线程概念、理解、控制

目录 一、认识线程 1.认识线程V1 2.认识线程V2 3.认识线程V3 4.认识线程V4 5.认识线程V5 二、线程控制 1.前言 2.创建线程 3.线程等待 4.线程终止 5.线程分离 三、线程理解 一、认识线程 1.认识线程V1 借用大多数计算机教材的话&#xff0c;线程是进程的一个执行…...

Postman如何流畅使用DeepSeek

上次写了一篇文章是用chatBox调用api的方式使用DeepSeek&#xff0c;但是实际只能请求少数几次就不再能给回响应。这回我干脆用最原生的方法Postman调用接口请求好了。 1. 通过下载安装Postman软件 postman下载(https://pan.quark.cn/s/c8d1c7d526f3)&#xff0c;包含7.0和10…...

K8S下载离线安装包所需文件

下载相关文件 官网下载地址集合https://kubernetes.io/zh-cn/releases/download/ 下载相关镜像 官网镜像描述 所有 Kubernetes 容器镜像都被部署到 registry.k8s.io 容器镜像仓库。 容器镜像支持架构registry.k8s.io/kube-apiserver:v1.32.0amd64, arm, arm64, ppc64le, …...

探索Hugging Face:开源AI社区的核心工具与应用实践

引言&#xff1a;AI民主化的先锋 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;Hugging Face已成为开源社区的代名词。这个成立于2016年的平台&#xff0c;通过提供易用的工具和丰富的预训练模型库&#xff0c;彻底改变了开发者使用和部署AI模型的方式。截至202…...

【操作系统】深入理解Linux物理内存

物理内存的组织结构 我们平时所称的内存也叫随机访问存储器也叫 RAM 。RAM 分为两类&#xff1a; 一类是静态 RAM&#xff08; SRAM &#xff09;&#xff0c;这类 SRAM 用于 CPU 高速缓存 L1Cache&#xff0c;L2Cache&#xff0c;L3Cache。其特点是访问速度快&#xff0c;访…...

npm 私服使用介绍

一、导读 本文主要介绍 npm 私服的使用&#xff0c;至于 npm 私服搭建的过程&#xff0c;可以看本人之前的文章《Docker 部署 verdaccio 搭建 npm 私服》 二、前置条件 npm私服地址&#xff1a;http://xxx.xxx.xxx.xxx:port/ 三、本地 npm 源切换 使用nrm&#xff0c;可以方…...

安全筑基,智能赋能:BeeWorks IM引领企业协同新纪元

在数字经济高速发展的今天&#xff0c;企业通讯系统已从单纯的信息传递工具演变为支撑业务创新的核心平台。传统通讯工具在安全性、智能化、协同性等方面的不足&#xff0c;严重制约着企业的数字化转型进程。BeeWorks IM系统以其创新的技术架构和智能化功能&#xff0c;正在重新…...

水务+AI应用探索(一)| FastGPT+DeepSeek 本地部署

在当下的科技浪潮中&#xff0c;AI 无疑是最炙手可热的焦点之一&#xff0c;其强大的能力催生出了丰富多样的应用场景&#xff0c;广泛渗透到各个行业领域。对于水务行业而言&#xff0c;AI 的潜力同样不可估量。为了深入探究 AI 在水务领域的实际应用成效&#xff0c;切实掌握…...

[JVM篇]垃圾回收器

垃圾回收器 Serial Seral Old PartNew CMS(Concurrent Mark Sweep) Parallel Scavenge Parallel Old G1 ZGC...

SQL Server:查看当前连接数和最大连接数

目录标题 **1. 查看当前连接数****使用系统视图****使用动态管理视图** **2. 查看最大连接数****通过配置选项****通过服务器属性** **3. 查看连接数的实时变化****4. 设置最大连接数****5. 查看连接的详细信息****6. 使用 SQL Server Management Studio (SSMS)****7. 使用 SQL…...

DeepSeek应用——与PyCharm的配套使用

目录 一、配置方法 二、使用方法 三、注意事项 1、插件市场无continue插件 2、无结果返回&#xff0c;且在本地模型报错 记录自己学习应用DeepSeek的过程&#xff0c;使用的是自己电脑本地部署的私有化蒸馏模型...... &#xff08;举一反三&#xff0c;这个不单单是可以用…...

【第15章:量子深度学习与未来趋势—15.3 量子深度学习在图像处理、自然语言处理等领域的应用潜力分析】

一、开篇:为什么我们需要关注这场"量子+AI"的世纪联姻? 各位技术爱好者们,今天我们要聊的这个话题,可能是未来十年最值得押注的技术革命——量子深度学习。这不是简单的"1+1=2"的物理叠加,而是一场可能彻底改写AI发展轨迹的范式转移。 想象这样一个…...

多模态基础模型训练笔记-第一篇InternVL-g

一、TL&#xff1b;DR 将之前所有训练过的大模型的过程都总结和回忆一下&#xff0c;遇到的坑别忘了 二、问题记录 还是注意镜像的选择&#xff0c;选择社区最火的镜像&#xff0c;然后下载好对应的数据&#xff0c;主要显卡的选择&#xff0c;这个时候4090已经带不动了&…...

MyBatis:动态SQL高级标签使用方法指南

一、引言 目前互联网大厂在搭建后端Java服务时&#xff0c;常使用Springboot搭配Mybatis/Mybatis-plus的框架。Mybatis/Mybatis-plus之所以能成为当前国内主流的持久层框架&#xff0c;与其本身的优点有关&#xff1a;支持定制动态 SQL、存储过程及高级映射&#xff0c;简化数…...

使用grafana v11 建立k线(蜡烛图)仪表板

先看实现的结果 沪铜主力合约 2025-02-12 的1分钟k线图 功能介绍: 左上角支持切换主力合约,日期,实现动态加载数据. 项目背景: 我想通过前端展示期货指定品种某1天的1分钟k线,类似tqsdk 的web_gui 生成图形化界面— TianQin Python SDK 3.7.8 文档 项目架构: 后端: fastap…...

ubuntu 安装 Redis

一、下载 Redis 压缩包&#xff0c;wget http://download.redis.io/releases/redis-5.0.14.tar.gz 也可以去官网下载别的版本 https://redis.io 二、解压文件&#xff0c;tar -zxvf redis-5.0.14.tar.gz 三、编译安装&#xff08;使用压缩包的方式需要编译安装&#xff09;&…...

利用docker-compose一键创建并启动所有容器

简介 在开发复杂的分布式应用时&#xff0c;通常需要同时运行多个服务&#xff08;如数据库、缓存、Web 应用等&#xff09;。Docker Compose 提供了一种简便的方式来定义和运行多容器 Docker 应用程序。通过一个 docker-compose.yml 文件&#xff0c;您可以配置应用程序的服务…...

mysql开启gtid并配置主从

默认主从都开启了bin log. 1.主从都在/etc/my.cnf中加入并重启服务 gtid_mode ON enforce_gtid_consistency ON 2.在主库创建用户并授权 create user slave identified with mysql_native_password by 123456 mysql>GRANT REPLICATION SLAVE ON *.* to slave% identified…...

redis sentinel模式 与 redis 分片集群 配置

Redis 最低为5.0版本&#xff0c;以下为6.2.6版本信息。 模式 高可用性 数据分片 部署复杂度 适用场景 Sentinel 模式 高 无 中等 中小规模&#xff0c;需要高可用性 集群模式 高 支持 复杂 大规模&#xff0c;需要高…...

2025最新在GitHub上搭建个人图床,保姆级图文教程,实现图片高效管理

文章目录 &#x1f30d;一. 图床❄️1.什么是图床❄️2.图床能解决什么问题&#xff1f; &#x1f30d;二. 在github上面创建图床&#x1f30d;三. PicGo❄️1. PicGo介绍❄️ 2. 下载与安装❄️3. 配置图床 ❄️3.错误解决问题1问题2问题3问题4 &#x1f30d; 四. Typora❄️…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...