Linux基础内容(24) —— 线程概念

news2024/11/17 16:03:58

Linux基础内容(23)—— 信号补充与多线程交接知识_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131275661?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22131275661%22%2C%22source%22%3A%22m0_63488627%22%7D

目录

 1.基本介绍

1.虚拟地址和页表的作用

2.页表的结构

2.认识线程

1.进程与线程笼统概念

2.Linux下的线程以及进程的重新认识

3.总结线程知识

4.演示进程

5.线程创建

1.共享资源

2.私有资源

3.线程实现反映的特性

1.进程vs线程

2.一般应用

3.缺陷

4.验证


1.基本介绍

1.虚拟地址和页表的作用

1.虚拟地址是进程能看到的资源窗口,进程能知道在虚拟地址内部每一个地址的含义

2.页表则是分配了进程真正能看到的资源,通过所谓的映射关系映射到物理内存中

3.合理的地址空间和页表对资源进行划分,使得我们能对进程的资源进行充分管理

2.页表的结构

1.在此之前我们还需要对物理内存的划分进行说明。如果单纯的将物理内存看为二进制,获取也是一个字节一个字节的获取,那么该性能不会体现出当代的电脑如此灵活。说明划分并不是简单的划分。

2.事实上,物理内存也是被操作系统管理的,既然要被管理就应该先被组织起来。物理内存被划分为以4KB为单位的页框,这样也是为了方便读取,节省时间。那划分出页框后,操作系统则将其管理成数据结构struct Page用于管理

3.那我们知道物理内存是4KB为单位的页框后,那么其来源的磁盘,数据从磁盘转移到物理内存中其实也是以4KB为单位转移的,不过要知道磁盘的4KB被叫做页帧

知道以上的空间管理后我们就能对页表有更深的理解了

1.其实页表也是一种管理的结构,既然是管理结构就绕不开属性,不过属性中不是只有内存而已,它还包括了命中判定,读写权限,内核态用户态状态判断的属性

2.虚拟地址由32位为例子。32位,说明地址有2的32次方中结果。我们的页表总不能映射2的32次方个以上面表为基础的结构吧,这样的地址空间直接消耗的比虚拟空间还要大,显然不现实

3.首先物理地址的32位被划分为10,10,12。其中第一个10位表示有2的10次方个页目录作为索引,将32位强行分为2的10次方个。第二个10位则是每一个页目录索引到另外2的10次方个的页表。随后页表指向物理内存的页框,页框以4KB划分,而2的12次方字节正好是4KB,这样就得到管理的最终结构了

2.认识线程

1.进程与线程笼统概念

1.最开始的理解对于进程就是所谓的运行的文件,该文件的属性和大小都是进程的一部分

2.task_struct结构通过页表映射找对需要被调度的函数。那么我们能引出线程的概念,如果我们需要不同的task_struct结构管理一个虚拟地址空间,通过划分来管理不同的执行部分,这样就得到了不同的执行流,而这些执行流就是所谓的线程。那么线程就是有进程划分出来,管理同一个虚拟地址空间的不同段的执行流。

3.而这种单个"进程"(线程)的执行力度是比之前描述的进程要细

2.Linux下的线程以及进程的重新认识

1.既然线程也是一种结构,那么我们就需要对它进行组织与管理。我们现在知道的是线程是进程划分出来的类似于子集。

2.对于windows来说,其实线程是单独做出一个数据结构来管理的;而Linux下,由于进程与线程的数据结构高度耦合,并且对于操作系统执行的角度来说,无论执行线程还是进程都是顺序的执行指定函数,所以Linux采用的是和进程一套数据结构

3.那么此时我们对线程和进程重新进行描述了。对于进程,虽说是执行的文件没错,但是在内核中看来,进程就是用来分配系统资源的基本实体,它包括了文件代码,系统的调用,cpu调用文件时的临时数据,线程,虚拟地址空间以及页表等

4.操作系统中的线程就是CPU真正调度的基本单位

5.由上面我们所理解的真正的CPU真正的调度的基本单位是线程,那么最之前所介绍的进程调度所有的信息和资源其实也是符合条件的,只是但是的场景下操作系统只有一个执行流,这个执行流就是我们最开始说的进程,其实也是线程。因为Liunx下不管进程和线程,只看其结构给出的进行服务调度

6.当前由于操作系统不关心线程还是进程,task_struct其实就是轻量级进程,Linux的线程就是轻量级进程。

3.总结线程知识

特点

1.Linux中没有真正意义的线程,它是将轻量化进程,是Linux自己处理线程的一个方案

2.不过在Linux看来,进程线程一视同仁

3.其好处其实是,简单,降低维护成本,可考虑高

缺点

1.操作系统设置的线程是轻量化进程,但是用户如果使用也只会考虑线程

2.Linux不能提供线程的系统调用接口因为根本没有,它只能提供轻量级进程

4.演示进程

thread:输入轻量级进程地址

attr:手动修改线程的属性配置

start_routine:线程执行的线程

arg:传入函数中的数据

void *thread_routine(void *args)
{
    const char *name = (const char *)args;
    while (true)
    {
        cout << "我是新线程, 我正在运行! name: " << name << endl;
        sleep(1);
    }
}

int main()
{
    // typedef unsigned long int pthread_t;
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread one");
    assert(0 == n);
    (void)n;

    // 主线程
    while (true)
    {
        // 地址 -> ?
        char tidbuffer[64];
        snprintf(tidbuffer, sizeof(tidbuffer), "0x%x", tid);
        cout << "我是主线程, 我正在运行!, 我创建出来的线程的tid: " << tidbuffer << endl;
        sleep(1);
    }

    return 0;
}

此时编译是通过不了的

这是因为,操作系统没有线程的真正意义,也就是说当前的pthread的创建不是操作系统的调用接口,而是库提供给用户使用的。所以我们需要在编译时将库动态链接进去。-lpthread

 在用户和操作系统之间,已经提供了完整的库可以被调用

查看进程,我们发现,只有一个pthread的进程,跟我创造了两个轻量级进程完全没有对应上

ps -aL才是查看线程的,LWP表示轻量级进程

此时我们会发现有一个线程PID和LWP是完全一样的线程,该线程为主线程,其余的相同CMD的线程都是子线程。那么此时我们就能兼容起进程的内容。操作系统不关心到底操作的是进程还是线程,我们kill进程其实就是kill掉只有主线程的PID,这个PID既是进程又是线程,操作系统kill的都是轻量级进程,不过在这样的设计下一视同仁。

5.线程创建

1.共享资源

一般而言,几乎所有的资源都被所有的资源所共享

1.函数

2.全局变量

包括文件描述符表,每种信号的处理方式,当前工作目录,用户id和组id
 

int g_val = 0;

std::string fun()
{
    return "我是一个独立的方法";
}

void *thread_routine(void *args)
{
    const char *name = (const char *)args;
    while (true)
    {
        fun();
        cout << "我是新线程name: " << name << " : "<< fun()  << " : " << g_val++ << " &g_val : " << &g_val << endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, thread_routine, (void *)"thread one");
    assert(0 == n);
    (void)n;

    while (true)
    {
        char tidbuffer[64];
        snprintf(tidbuffer, sizeof(tidbuffer), "0x%x", tid);
        cout << "我是主线程 tid: " << tidbuffer << " : " << g_val << " &g_val : " << &g_val << endl;
        sleep(1);
    }

    return 0;
}

2.私有资源

哪部分资源是各个线程独有的?

1.PCB属性私有,因为每一个轻量级进程都是独立

2.轻量级线程相互转换运行,动态运行,其中的上下文结构是独立的

3.有独立的栈结构,用于保存所有的临时变量,有属于自己的私有数据

包括线程ID,一组寄存器,栈,errno,信号屏蔽字,调度优先级

3.线程实现反映的特性

1.进程vs线程

1.进程的创建比线程的创建要麻烦。由于创造进程需要将虚拟地址空间,页表,寄存器上下文等数据全部拷贝,所用的成本变高。而线程只需要创造一个线程即可。

2.进程的来回切换比起线程的来回切换耗费工作量多。

进程切换需要切换页表,虚拟地址空间,切换PCB和上下文;

线程只需要切换PCB和上下文;

上面的切换页表和虚拟地址空间不占消耗工作量的大头,在CPU中,为了使得寄存器和内存之间的拷贝效率更高,其中会有cache(高速缓存)来进行缓冲,而针对线程,绝大多数的资源是共享的,意味着cache中的热点数据几乎相同,那么切换时cache不需要完全更新;对于进程就不一样了,由于全部都需要更新,工作量就更高

2.一般应用

1.针对计算密集型应用(多访问CPU资源),通过分解出多线程

2.针对I/O密集型应用(多访问IO资源),用不同的线程进行I/O操作

3.缺陷

1.性能损失:线程最好与核数相互匹配,核指的是cpu中运算单元的个数。如果计算密集型
线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。进程则是看cpu数
2.健壮性降低:进程退出不影响其他进程,而线程退出会影响其他线程

3.缺乏访问控制:进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
4.编程难度提高:编写与调试一个多线程程序比单线程程序困难得多

4.验证

健壮性问题

void *start_routine(void *args)
{
    string name = static_cast<const char *>(args); // 安全的强制类型转换
    while (true)
    {
        cout << "new thread success, name: " << name << endl;
        sleep(1);
        int* p = nullptr;
        *p=0;
    }
}

int main()
{
    pthread_t id;
    pthread_create(&id, nullptr, start_routine, (void *)"thread new");

    while (true)
    {
        cout << "new thread success, name: main thread"<< endl;
        sleep(1);
    }

    return 0;
}

运行该代码,主线程是没有问题的,只是子线程中指针非法访问。那么整个进程就会因为线程的问题而整体退出。这是因为信号其实是进程的信号,那么接收信号的实体也是进程,而线程的错误也意味着进程的错误,进程发生错误被回收,同理线程也会一并被回收,这样也就解释了为什么健壮性不强,因为动一发而牵全身。

轻量级进程接口

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【无监督学习】0、有监督学习、无监督学习、半监督学习

文章目录 一、有监督学习二、半监督学习三、无监督学习3.1 对比式学习 一、有监督学习 有监督学习最大的特点就是数据集是带标签的&#xff0c;如有监督分类任务&#xff0c;就是给每张图都分配一个真实标签&#xff0c;表示这张图是 dog、cat 或者是 bird。 而标签的作用就是…

Git基本操作命令

目录 一、简介 二、基本命令使用 (1) git add ---将该文件添加到暂存区 (2) git status --- 命令用于查看在上次提交之后是否有对文件进行再次修改 (3) git diff -- 比较文件在暂存区和工作区的差异 (4) git commit --- 将暂存区内容添加到本地仓库中 (5) git reset --…

前端实现实时数据更新:EventSource

前言 大看板相信很多人都做过&#xff0c;通常就是用来展示数据的。最初一些同事&#xff08;包括我自己&#xff09;都是通过定时器来实现的&#xff0c;每隔多长时间发送一次请求。后来用户说页面不刷新或者是页面卡死了&#xff0c;讨论的解决方案是改成WebSocket实时推送消…

AI绘图软件分享:Midjourney 基础教程(四)参数进阶

大家好&#xff0c;我是权知星球&#xff0c;今天我们继续来学习Midjourney 基础教程&#xff08;四&#xff09;&#xff1a;Midjourney 参数进阶。 通过前⼏篇⽂章的学习&#xff0c;我们知道了&#xff0c;想要掌握 Midjourney AI 绘画技术&#xff0c;先需要学习掌握常⽤的…

还在烦恼代码写不出来?低代码助力实现“无码”搭建系统平台

摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 据说… 每敲出来一行代码 就有一根头发离我而去… 而每解决掉一个bug 就有一个毛囊开始休养生息… 程序猿&#xff0c;一个让人既爱又…

USR-C216配置客户端模式,手机接收数据

若是不清楚现在模块什么配置可先恢复出厂设置&#xff0c;将nReload拉低3S即可。 此时模块发出热点名字为USR-C216,无密码 电脑连接后在浏览器输入10.10.100.254&#xff0c;进入后密码和用户名为admin

多数人都不会用,有了这些视频APP,再也不担心失效!

阿虚储物间里一大热门下载内容就是影视类APP了 但相信有这类需求的粉丝都知道&#xff1a;这类APP要么你忍受烦人的广告&#xff0c;要么就找去广告版&#xff0c;但去广告版有个最大的问题就是经&#xff01;常&#xff01;失&#xff01;效&#xff01; 其实阿虚早就介绍过…

窗口层级树的构建

窗口层级树的构建 参考&#xff1a; android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer第二节 在上一节dumpsys activity containers中&#xff0c;层级树中有如下的标识符&#xff1a; WindowedMagnificationHideDisplayCutoutOneHandedHideDisplayCut…

【软考网络管理员】2023年软考网管初级常见知识考点(4)-局域网基本概念

涉及知识点 局域网特点&#xff0c;局域网体系结构&#xff0c;局域网拓扑结构&#xff0c;局域网传输介质&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 文章目录 涉及知识点前言一、局域网的特点二、局域网体系…

Apache RocketMQ EventBridge:构建下一代事件驱动引擎

作者&#xff1a;沈林 前言 事件驱动&#xff0c;这个词在部分人印象中&#xff0c;它是一个过时的技术——没什么新意。从时间上看&#xff0c;确实也是这样&#xff0c;上世纪 60 年代&#xff0c;事件驱动就已经被正式提出&#xff0c;经常会被在 GUI 编程中。但是在有些人…

IO总线控制器模块在工业自动化中的关键应用

IO总线控制器模块是工业自动化系统中的关键组件&#xff0c;其功能和特点包括&#xff1a; IO集成&#xff1a;IO总线控制器模块通过支持多种IO接口和协议&#xff0c;实现了各种数字和模拟信号的集成和控制。它能够与各种传感器、执行器和其他设备进行通信和数据交换。 实时性…

TCP协议的滑动窗口具体是怎样控制流量的?

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言TCP协议概述滑动窗…

小航助学2023年6月GESP_C++四级试卷(含题库答题软件账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 单选题2.0分 删除编辑附件图文 答案:D 第1题高级语言编写的程序需要经过以下&#xff08; &#xff09;操作&#xff0c;可以生成在…

1分钟教你从0-1搭建Monorepo多包项目

1、monorepo是啥 在了解Monorepo之前&#xff0c;先说一下Multirepo Multirepo&#xff1a;指定的是不同项目由不同的仓库来存放管理 每个仓库都维护着各项目的npm包依赖 Monorepo指的是包含多个项目的单个仓库。 各个项目可以单独运行、打包、发布 Multirepo&#xff1a;分散式…

【CV】EfficientNet相比resnet有哪些优点,什么是深度可分离卷积

目录 前言使用深度可分离卷积普通卷积的计算参数量深度可分离卷积分为两个步骤&#xff1a;深度卷积和逐点卷积 使用多个缩放因子使用 Swish 激活函数 前言 高效的神经网络主要通过&#xff1a;1. 减少参数数量&#xff1b;2. 量化参数&#xff0c;减少每个参数占用内存 目前的…

Transformer中的Q,K,V

Query&#xff0c;Key&#xff0c;Value的概念取自于信息检索系统&#xff0c;举个简单的搜索的例子来说。当你在某电商平台搜索某件商品&#xff08;年轻女士冬季穿的红色薄款羽绒服&#xff09;时&#xff0c;你在搜索引擎上输入的内容便是Query&#xff0c;然后搜索引擎根据…

【历史上的今天】6 月 25 日:笔记本之父诞生;Windows 98 发布;通用产品代码首次商用

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2023 年 6 月 25 日&#xff0c;在 1951 年的这一天&#xff0c;世界上第一部彩色电视节目播出。电视经过了许多年的发展&#xff0c;人类的娱乐途径随着互联网的到来变…

SpringBoot 如何使用 Spring Test 进行集成测试

SpringBoot 如何使用 Spring Test 进行集成测试 简介 在开发过程中&#xff0c;单元测试是不可或缺的&#xff0c;它可以帮助我们及时发现代码的问题并进行修复&#xff0c;从而提高代码的质量和可维护性。但是&#xff0c;单元测试只能测试单个方法或类的功能&#xff0c;无…

HTTP | 深度解析HTTPS比HTTP 更安全的原因

目录 1. 不安全的 HTTP &#x1f333; 为什么 HTTP 协议不安全呢&#xff1f; 容易被窃听 容易被篡改 容易被伪造身份 &#x1f333; HTTPS 是如何解决以上安全性问题的呢&#xff1f; 数据加密 完整性摘要 数字证书 2. 加密算法 &#xff08;1&#xff09;对称加密…

Springboot宠物医院管理系统的设计与实现-计算机毕设 附源码84724

Springboot宠物医院管理系统的设计与实现 摘 要 现如今生活质量提高&#xff0c;人们追求精神健康&#xff0c;与家中宠物朝夕相处&#xff0c;感情深厚&#xff0c;宠物渐渐成了我们身边的朋友。因而宠物生病了&#xff0c;需要去看病&#xff0c;自古医院救死扶伤&#xff0c…