Liunx:线程

news2024/11/28 18:36:25

        我们先说一个程序是怎么执行的:

        我们编写好一个代码,经过预编译,编译,汇编,连接,形成一个二进制文件被写进磁盘中,通常我们把他叫做可执行程序。 我们可以双击运行,运行需要经过几个步骤,先将二进制程序从磁盘加载到内存中,然后操作系统建立进程PCB。

        我们知道,程序被编译连接好后,都是一些二进制指令,这些指令在被加载到内存中后,每个指令在内存中都可以用一个地址来定位,这个地址叫做物理地址。同时,我们编译好的指令,在这个可执行文件中,有一个相对位置,具体点说,汇编形成的指令我们从0开始给它编号,每条指令在可执行程序文件中的位置,就是虚拟地址。

        进程在liunx中用一个结构体来定义,该结构体中有一个成员叫做页表,每一个程序都有自己各自的页表,页表的作用是完成虚拟地址到物理地址的映射。通俗的说,在文件中编号为1的指令,在物理地址中的位置是0x00456,当我运行1号指令是,通过页表查询,我知道1号指令在内存的0x00456位置,然后加载到cpu执行。如果程序中访问了一个虚拟地址,但是该虚拟地址在页表中没有相应的物理地址,操作系统就会给你抛异常或者报错。该页表的映射关系,是由操作系统来完成的。通过页表映射,一个程序只能访问内存中自己映射部分的地址。

        页表对于程序的意义在于提供了程序运行之间的高隔离性和独立性。假如说没有通过页表映射,程序可以直接访问物理内存,我在程序中随便来一个野指针随机的访问数据,你随机访问可能刚好是别的程序的数据,A程序随意篡改B程序的数据,这就会导致程序崩溃。所以,页表对于保护程序运行安全有着重要意义。在liunx中实现多线程,页表起着关键作用,所以这里详细说一下。

        说完页表,我们再回来。程序执行肯定是根据指令在文件中的相对位置顺序执行的,cpu每次执行完成一条指令的计算。我们假设程序中有两个函数,C和D,我想要计算机同时运行这一个文件中的两个功能怎么办?现实中的很多场景都是这样,就像在微信聊天的时候,你发信息的时候同样能接收信息。一个程序中同时运行两个函数,这就是线程的功能,也就是我们常说的并行执行。

        我们先来观察现象,下面是代码:

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

using namespace std;

void* threadRun(void* argc)
{

    while(1)
    {
        cout<<"new thread :"<<getpid()<<endl;
        sleep(1);
    }

    return nullptr;
    
}
int main()
{

    pthread_t tid;
    pthread_create(&tid,nullptr,threadRun,nullptr);


while(1)
{
    cout<<"main thread : "<<getpid()<<endl;
    sleep(1);
}
    
    return 0;
}

        主函数的前两行代码,在进程中创建了一个线程,创建线程肯定是要让他并行的执行一个功能,我们把threadRun函数传递给它,意思就是我创建一个线程,该线程完成的功能就是运行threadRun函数,但是该函数是一个死循环。然后再接着执行一个死循环。

        正常的逻辑是,代码顺序运行,只会运行第一个死循环,但是:

        看到没, 两个死循环是同时运行的。


        我们下面再说,liunx中的线程是如何设计的。

        想一下我cpu执行一个程序需要什么?代码,与代码运算相关的数据(保存在cpu的寄存器中),执行时我还可以能读取页表来访问内存中的数据等等,这些运行需要的所有东西都被囊括在PCB结构体中。如果我们对程序A建立一个PCB,然后A程序的代码中会有一行代码调用系统调用再创建一个PCB,把它叫做B,该PCB的结构中的代码与A相同,页表也相同,但是B只执行A文件中的一个功能,注意此时A程序的代码和数据都被加载到了内存中,也就是说,B可以直接通过页表访问A的代码和数据,并且只执行一部分功能。

        我们在进程说过,系统调用执行程序本质上就是加载程序相应的PCB到CPU中,当通过A创建好B的PCB之后,那么B,也就是对应到A程序的一部分功能就可以被系统调用执行。

        对于CPU来说,他调度的基本单位是一个PCB,我们为运行一个程序先创建了一个PCB,CPU调度该PCB又基于同一份代码文件创建了多个PCB,也就是线程,相应的线程执行这个代码文件的部分功能,那么通过这个操作,将原本一个较大的程序,分割成了多个较小的执行流,这些多个执行流共同构成了该程序(进程),所以我们说,线程具有比进程更小的粒度,线程是CPU调度的基本单位。一个进程可以不创建额外的线程而直接顺序执行代码。

        再补充一下,CPU调度进程,会为该进程的执行分配一个时间片,也就是这个进程可以在CPU上运行多长时间:

        单核时,实际上,一个进程被分割成多个线程执行时,线程也是轮询的在时间片范围内被CPU调度,只不过情况变成了,该程序在一个时间片上可能顺序执行整个程序的四分之一,变成多线程后,是代码中的每个功能都被执行了四分之一。

        从这也能看出,线程的执行不论是在时间上还是所占的资源上,粒度都比进程小。也能体现出来CPU执行的基本单位就是一个线程。

        还需要指出一点,创建多线程需要首先创建一个PCB,这个PCB结构体是基于整个代码文件来初始化自己内部的属性,包括在内存所占的空间,一个页表,文件inode等等,以上初始化属性的过程实际上就是系统在为程序的执行分配资源,我想说的是,CPU执行的基本单位是线程,但是为资源分配是以进程为单位的,以后线程的执行所需要的资源都相当于直接访问创建的第一个PCB(主线程)。


        在Liunx中,怎么将线程由概念描述并组织成具体数据结构呢?事实上,线程的结构与进程无论是在调度上还是在管理上都有着极高的相似性,liunx设计者在实现线程时复用了进程的数据结构和相应的一套算法,这只是设计者的选择,你当然也可以重新定义一个数据结构来描述线程并且适配一套算法。liunx直接用task_struct来组织描述tcb(thread chotrol block)。so,liunx中的执行流被叫做轻量级进程。

        到这里,线程的概念基本建立起来了,接下来对于线程的同步与互斥,锁,临界资源等概念都是在线程在具体实践中为出现的某些情形或者为解决某一问题而定义和建立的。

        

        

       

                

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

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

相关文章

Modern C++ std::mutex底层原理

前言 我时常有这样的疑问&#xff1a; std::mutex怎么就能保证后面的语句100%安全哪&#xff1f;CPU reordering就不会把这些语句重排到mutex前面执行&#xff1f;而且各个CPU都是有L1、L2缓存的&#xff0c;如果mutex后面要访问的的变量在这些缓存中怎么办&#xff1f; 带着…

sqlilabs第五十七五十八关

Less-57(GET - challenge - Union- 14 queries allowed -Variation 4) 手工注入 Less-58(GET - challenge - Double Query- 5 queries allowed -Variation 1) 手工注入 报错注入就可以&#xff08;布尔注入的话次数不够&#xff09;(所以我们前面需要做够足够的数据支持) 最后…

whistle代理+mock轻松解决“页面端“测试接口没数据难题

0、whistle是什么&#xff1f;怎么用&#xff1f; 自行百度&#xff0c;此处不再赘述&#xff01; 1、示例演示&#xff08;交易订单测试&#xff09; 背景和痛点最近在测试一个小需求&#xff0c;需要涉及订单侧服务商品库侧服务库存侧服务财务侧线下交易服务。痛点主要在订…

abap 将xstring转换成PDF展示

收到外围系统的xstring之后&#xff0c;如何在sap中将其打开呢 1.创建一个屏幕 2.绘制一个customer control 3.创建流逻辑 4.流逻辑如下&#xff1a; DATA: go_html_container TYPE REF TO cl_gui_custom_container, go_html_control TYPE REF TO cl_gui_html_viewer, lv_u…

66.Go从零搭建一个orm框架【简版】

文章目录 一&#xff1a;前置学习1、 为什么要用orm2、Golang里面是如何原生连接MySQL的3、ORM框架构想 二: 开始造1、连接Connect2、设置/读取表名Table/GetTable3、新增/替换Insert/Replace4、条件Where5、条件OrWhere6、删除Delete7、修改Update8、查询9、设置查询字段Field…

序列到序列模型

一.序列到序列模型的简介 序列到序列&#xff08;Sequence-to-Sequence&#xff0c;Seq2Seq&#xff09;模型是一类用于处理序列数据的深度学习模型。该模型最初被设计用于机器翻译&#xff0c;但后来在各种自然语言处理和其他领域的任务中得到了广泛应用。 Seq2Seq模型的核…

介绍下Redis?Redis有哪些数据类型?

一、Redis介绍 Redis全称&#xff08;Remote Dictionary Server&#xff09;本质上是一个Key-Value类型的内存数据库&#xff0c;整个数据库统统加载在内存当中进行操作&#xff0c;定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作&#xff0c;Redis的性…

Spring框架的背景学习

Spring 的前世今生 相信经历过不使用框架开发 Web 项目的 70 后、80 后都会有如此感触&#xff0c;如今的程序员开发项目太轻松了&#xff0c;基本只需要关心业务如何实现&#xff0c;通用技术问题只需要集成框架便可。早在 2007 年&#xff0c;一个基于 Java语言的开源框架正…

Python环境下基于自适应滤波器的音频信号(wav格式)降噪方法

Python的集成环境我一般使用的是Winpython&#xff0c;Winpytho脱胎于pythonxy&#xff0c;面向科学计算&#xff0c;兼顾数据分析与挖掘&#xff1b;Anaconda主要面向数据分析与挖掘方面&#xff0c;在大数据处理方面有自己特色的一些包&#xff1b;Winpytho强调便携性&#x…

Python Tkinter Grid布局管理器用法

很多时候 Tkinter 界面编程都会优先考虑使用 Pack 布局&#xff0c;但实际上 Tkinter 后来引入的 Grid 布局不仅简单易用&#xff0c;而且管理组件也非常方便。 Grid 把组件空间分解成一个网格进行维护&#xff0c;即按照行、列的方式排列组件&#xff0c;组件位置由其所在的行…

MySQL、Oracle 生成随机ID、随机数、随机字符串

目录 1 MySQL 生成随机ID1.1 生成 唯一的随机ID&#xff1a;UUID()1.2 生成随机数&#xff1a;RAND()1.2.1 RAND()&#xff1a;返回一个介于0和1之间的随机浮点数1.2.2 FLOOR(RAND() * 100)&#xff1a;返回一个介于0和99之间的随机整数1.2.3 LPAD(FLOOR(RAND() * 99999999), 8…

行为型设计模式——中介者模式

中介者模式 中介者模式主要是将关联关系由一个中介者类统一管理维护&#xff0c;一般来说&#xff0c;同事类之间的关系是比较复杂的&#xff0c;多个同事类之间互相关联时&#xff0c;他们之间的关系会呈现为复杂的网状结构&#xff0c;这是一种过度耦合的架构&#xff0c;即…

【上分日记】第380场周赛(数位dp+ KMP + 位运算 + 二分 + 双指针 )

文章目录 前言正文1.3005. 最大频率元素计数2.3007.价值和小于等于 K 的最大数字3.3008. 找出数组中的美丽下标 II 总结尾序 前言 本场周赛&#xff0c;博主也只写出两道题(前两道, hhh菜鸡勿喷)&#xff0c;第三道涉及位运算 &#xff0c;数位dp&#xff0c;第四道涉及KMP。 下…

c语言[]优先级大于*优先级

本博文源于笔者正在学习的c语言[]优先级大于*优先级.在定义二维数组时&#xff0c;a1与[]号结合后&#xff0c;谁的优先级更高&#xff0c;是本博文探讨的话题 博文来源 想要看看*与[]谁的优先级更高 博文代码 #include<stdio.h> #include<stdlib.h> int main(…

OAuth 2.0 - 微信登录

一、概述 1、什么是OAuth 2.0 OAuth (Open Authorization) 是一个关于授权 (athorization) 的开放网络标准。 允许用户授权第三应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方。OAuth在全世界得到广泛应用&#xff0c;目前的版本…

R语言【paleobioDB】——pbdb_orig_ext():绘制随着时间变化而出现的新类群

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_orig_ext (data, rank, temporal_extent…

核对表:基本数据类型CHECKLIST:Fundmental Data

核对表&#xff1a;基本数据类型CHECKLIST:Fundmental Data 数值概论 代码中避免使用神秘数值吗&#xff1f; 代码考虑了除零错误吗&#xff1f; 类型转换很明显吗&#xff1f; 如果在一条语句中存在两个不同类型的变量&#xff0c;那么这条语句会像你期望的那样求值吗&#x…

JMeter 相关的面试题

1、什么是 JMeter&#xff1f; 它是一个开源的负载和性能测试工具&#xff0c;用于对软件、Web应用程序、API、数据库等进行压力测试。 2、JMeter 的优势是什么&#xff1f; JMeter具有以下优势&#xff1a; 开源免费&#xff1a;JMeter是开源工具&#xff0c;无需付费使用。…

使用 Elasticsearch 和 LlamaIndex 进行高级文本检索:句子窗口检索

2023 年是检索增强生成 (RAG) 的一年&#xff0c;人们探索了许多用例&#xff0c;并使用该技术开发了数百种产品。 从 Q/A 聊天机器人到基于上下文的代理&#xff0c;RAG 的使用一直是 LLM 申请快速增长的主要因素。 支持不断发展的社区以及 Langchain 和 LlamaIndex 等强大框架…

vue-cli解决跨域

在vue.config.js中 找到devServer 在devServer中创建proxy代理 proxy:{ path&#xff08;路径中包含这个path就会导航到target的目标接口&#xff09;&#xff1a;{ target:"目标接口" } } 例&#xff1a; 1 同源策略只针对于浏览器&#xff0c;代理服务器到后端接…