初识Linux · 线程概念

目录

前言:

线程的背景

线程的概念和Linux中的线程实现

线程杂谈


前言:

Linux的学习从开始到现在,我们已经经历了许多大boss,从一开始的熟悉指令,到第一次在gcc环境下编译C语言的代码,到理解文件系统,比如理解了文件的权限,万物皆文件的概念,此时,是我们经历的第一次大boss,文件系统。

之后,我们从shell开始慢慢理解Linux的系统内核部分,最典型的是我们慢慢开始理解了什么是进程,从pcb->task_struct到mm_struct地址空间,到页表部分,最后我们从物理内存出发,一步一步的理解了程序的地址,之后,我们学习了进程的状态,学习了进程的控制,学习了进程等待,学习了进程终止,以及进程的各种信息,比如Pid,这是第二次大boss。

今天,我们学习的是Linux中的第3个大boss,线程。线程我们同样,从概念入手,再到线程的控制,线程同步,线程互斥等,和前两个一样,都是需要我们反反复复学习的知识点。

那么,话不多说,本文作为线程的概念篇,主要是解释线程中的概念,并且结合少许的代码。

进入第一个主题吧!线程的概念。


线程的背景

介绍线程概念我们打算从地址空间入手,在地址空间篇章,我们就提及到过,地址空间我们是要多次介绍的,一共要介绍4次左右,今天就是第四次。

我们知道,之前对于地址空间的理解就是:

这个图我们已经十分熟络了,通过页表和MMU可以将虚拟内存和物理内存建立某种联系。可是,今天我们对于页表要理解的更深层一点。

假设在磁盘中有一个hello.o,它是文件吧?那么既然他是文件,它就应该有自己的inode,它也应该存在于物理内存中。既然是和物理内存挂钩,在前文介绍的磁盘管理中,分为扇区等区域,并且是以4kb的大小进行管理。此时,真实的数据块加载到了物理内存里面,通过某种方式,和虚拟内存建立了联系。

那么,我们不妨来解析一下虚拟内存,我们将虚拟内存分为三部分:0000 0000 00,前10位是第一部分,00 0000 0000,中间10位,是第二部分,0000 0000 0000是第三部分。

好吧,在此之前我们其实还是应该再深度解析一下物理内存。

磁盘中的文件的数据是以4kb的方式存在的,我们将每个物理内存叫做页框,每个文件的数据块叫做页帧,其实现在操作系统的书已经没有区分的那么多了。

对于IO来说,IO的基本单位是4kb,OS要进行内存管理的话,不是以字节的方式管理的,而是以内存块的方式管理的,所以文件的数据块,物理内存的页框都是内存管理的对象。

那么OS应该如何管理页框页帧呢?

当然是先描述再组织。在Linux中有一种结构体是struct page,里面存的就是页框的信息。

在Linux的源码里应该如何管理呢?已经描述好了,那么使用一个数组就管理起来了。

现在我们在来刨析虚拟内存,前10个比特位,其实是指向的页目录,我们是拿32位机器举例,所以页目录实际上是由1024个,那么一个一个的页目录,指向了一个一个的页表,对于虚拟地址的中间10位,指向的就是页表,对于后12位的虚拟地址,就是先定位到了页目录之后,才好定位到页框的位置,这样,就能通过虚拟地址找到物理内存了。

那么,什么是函数呢?或者说,虚拟地址的本质是什么呢?

其实在mm_struct中,正文的代码本来就是由一个一个的地址构成的,对于函数来说,不过是一连串的地址而已。所以对于代码数据划分的本质,不过是一种对于资源的划分!  


线程的概念和Linux中的线程实现

上面其实是对于页表的一种重新理解,可能有人觉得和今天的主题线程没有关系,实则不然,因为今天实际上会对之前进程的理解有一个颠覆性的理解。

在深入了解操作系统这本书里面说的好,进程是一种抽象。我们之前认为的进程是task_struct + mm_struct + 页表集合等。认为进程 = 内核数据结构 + 自己的代码和数据。

可是,在内核的观点里面,认为进程实际上是承担分配系统资源的基本实体。

今天就不讲故事了,我们直接说,以前认为task_struct就是进程,认为cpu调度的时候就是调度的task_strcut。

实际上不是的,一个进程可以存在多个task_struct,而对于task_struct就是Linux中的线程,为什么说是Linux中的线程呢?因为对于windows来说,windows也有自己的线程标准。

我们这样理解吧,对于国家来说,分配资源的实体是一个一个的家庭,家庭中的许多成员就是一个一个的线程。

那么windows对于线程是提供了真实线程控制块,对于Linux来说,是直接复用的内核代码,不然单独创建线程控制块,增加管理成本,源码还要多写很多很多行。

所以Linux中的线程实际上是集成在进程里面的。所以之前理解的进程实际上是只有一个线程的进程,我们之后要学习的就是一个进程含有多个线程。

那么对于cpu来说,是否要区分什么是线程,什么是进程呢?因为task_strcut理解存放的是进程的信息,但是实际上进程执行任务的时候使用的是线程。

cpu是不用区分的,因为cpu看到的执行流<=进程。我们将Linux中的线程成为轻量级进程。

那么既然有了多进程,为什么还要多线程呢?

因为cpu内部调度的时候,时间片一到,进程切换需要存上下文吧?地址空间,页表全部都要切换吧?那么这个成本是不是十分高了就?如果使用的是多线程,线程之间共享的是地址空间,页表,切换的时候成本就很低了。所以这是多线程的优势。

但是就和家庭一样,一个线程如果奔溃了,其他线程也都是会崩溃的。


线程杂谈

说了那么多,我们总的看看吧?

使用函数我们可以创建线程,其实第一个参数不解释了,第二个参数我们设置为nullptr即可,对于第三个参数就是函数指针,信号那里我们也见过,第四个参数是线程的名字。

我们直接来一份代码:

int gval = 100;void *threadStart(void *args)
{while (true){sleep(1);std::cout << "new thread running..." << ", pid: " << getpid() << std::endl;// std::cout << "new thread running..." << ", pid: " << getpid()//           << ", gval: " << gval << ", &gval: " << &gval << std::endl;}
}
int main()
{srand(time(nullptr));pthread_t tid1;pthread_create(&tid1, nullptr, threadStart, (void *)"thread-new");// pthread_t tid2;// pthread_create(&tid2, nullptr, threadStart, (void *)"thread-new");// pthread_t tid3;// pthread_create(&tid3, nullptr, threadStart, (void *)"thread-new");// 主线程while (true){std::cout << "main thread running..." << ", pid: " << getpid() << std::endl;// gval++;sleep(1);}return 0;
}

按照平常,我们直接g++是编译不过去的,因为它需要链接库,没想到到,重制版介绍为什么。

所以需要在Makefile文件里面加-lpthread

按照常理来说,两个死循环是不会同时打印的,可是一个进程使用两个线程调用不同的任务,就可以同时打印了:

像这样。

那么我们定义一个全局变量,看看g_val的变化:

发现线程是共享数据的,也就是地址空间都是同一份,这个我们也成功验证了。

当我们输入ps -aL指令,我们能查看线程的部分信息,可以发现和进程Pid相等的线程实际上是主线程,其他的是非主线程了,那么提问了,对于cpu来说,调度的时候看的是pid还是lwp呢?

当然是lwp了,毕竟是线程来执行的任务。

这里提及一个非常重要的点:

线程虽然共享了许多资源,但是线程私有的部分有一组寄存器,栈。前者要存储硬件的上下文,后者是线程运行的时候会形成各种临时变量,肯定都会被自己的线程保存在自己的栈区里。

本文不过是对线程的非常粗略的概念理解,请各位佬不要介意没有解释清楚大部分知识,重制版一定非常清晰的介绍清楚了。


感谢阅读!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ROS VRRP软路由双线组网方式

虚拟路由冗余协议 Virtual Router Redundancy Protocol (VRRP)&#xff0c;MikroTik RouteROS VRRP 协议遵循 RFC 2338。 VRRP 协议是保证访问一些资源不会中断&#xff0c;即通过多台路由器组成一个网关集合&#xff0c;如果其中一台路由器出现故障&#xff0c;会自动启用另外…

用 Python 与 Turtle 创作属于你的“冰墩墩”!

用 Python 与 Turtle 创作属于你的“冰墩墩”&#xff01; &#x1f980; 前言 &#x1f980;&#x1f40b; 效果图 &#x1f40b;&#x1f409; 代码 &#x1f409; &#x1f980; 前言 &#x1f980; 冰墩墩是2022年北京冬季奥林匹克运动会的官方吉祥物。以熊猫为原型&#x…

React 中使用 Axios 进行 HTTP 请求

下面是一个案例&#xff0c;展示如何在 React 中使用 Axios 进行 HTTP 请求&#xff0c;包括 GET 和 POST 请求的使用。 1. 安装 Axios 确保项目中已安装 Axios&#xff0c;可以通过以下命令安装&#xff1a; npm install axios2. 创建一个简单的 React 应用 项目结构&…

【GoogleChrome】在开发者工具中修改js、css并生效

以下网站有个登录验证cookie的js 按f12打开开发者工具&#xff0c;看到验证规则很简单 添加替换js的本地文件夹 允许权限 删除js并按ctrls保存&#xff0c;然后刷新页面&#xff0c;新js生效

CentOS操作系统下安装Nacos

CentOS下安装Nacos 前言 这在Centos下安装配置Nacos 下载Linux版Nacos 首先到Nacos的 Github页面&#xff0c;找到所需要安装的版本 也可以右键复制到链接&#xff0c;然后通过wget命令进行下载 wget https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-ser…

数据结构--跳表

跳表 原理实现 原理 跳表&#xff08;skiplist&#xff09;是一种链表&#xff0c;而链表查询的时间复杂度为O(n)&#xff0c;为了优化查询效率&#xff0c;我们可以让每相邻两个节点升高一层&#xff0c;增加一个指针&#xff0c;让指针指向下下个节点&#xff1a; 这样所有…

【学术论文投稿】JavaScript 前端开发:从入门到精通的奇幻之旅

【中文核刊&普刊投稿通道】2024年体育科技与运动表现分析国际学术会议(ICSTPA 2024)_艾思科蓝_学术一站式服务平台 更多学术会议论文投稿请看&#xff1a;https://ais.cn/u/nuyAF3 目录 一、引言 二、JavaScript 基础 &#xff08;一&#xff09;变量与数据类型 &am…

云计算实训室建设的必要性

一、云计算发展的背景 云计算作为一种新型的信息技术服务模式&#xff0c;通过互联网提供动态易扩展且通常是虚拟化的资源&#xff0c;涵盖了从基础设施服务&#xff08;IaaS&#xff09;、平台服务&#xff08;PaaS&#xff09;到软件服务&#xff08;SaaS&#xff09;等多个…

鼠标绘制轮廓

需要对label进行提升&#xff0c;新建MyLabel类&#xff0c;并将其提升到label控件上&#xff0c;详见上篇控件提升 mylabelmouse.h #pragma once #include <QtWidgets/QMainWindow> #include "ui_mylabelmouse.h" #include <QMenu> #include "My…

LLM( Large Language Models)典型应用介绍 1 -ChatGPT Large language models

ChatGPT 是基于大型语言模型&#xff08;LLM&#xff09;的人工智能应用。 GPT 全称是Generative Pre-trained Transformer。-- 生成式预训练变换模型&#xff1a; Generative&#xff08;生成式&#xff09;&#xff1a;可以根据输入生成新的文本内容&#xff0c;例如回答问题…

STM322完全学习——FSMC控制LCD显示屏

一、GPIO初始化 首先这个功能只有大容量的STM32系列有&#xff0c;C8T6是没有的。再就是FSMC这个使用的是GPIO的复用功能&#xff0c;下面先完成我们需要使用的GPIO的初始化 void TFTLCD_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_…

MongoDB数据备份与恢复(内含工具下载、数据处理以及常见问题解决方法)

一、工具准备 对MongoDB进行导入导出、备份恢复等操作时需要用到命令工具&#xff0c;我们要先检查一下MongoDB安装目录下是否有这些工具&#xff0c;正常情况下是没有的:)&#xff0c;因为新版本的MongoDB安装时不包含这些工具&#xff0c;需要我们手动下载安装。下载成功之后…

【C语言】volatile 防止编译的时候被优化

volatile 易变的 volatile是 C 和 C 中的一个类型修饰符&#xff0c;用于指示编译器该变量可能在程序之外被更改&#xff0c;因此不应对其进行优化。这在涉及硬件寄存器、信号处理或多线程编程时非常有用。 如果你做过单片机开发&#xff0c;你肯定写过这样的代码&#xff1a;…

el-table实现最后一行合计功能并合并指定单元格

效果图如下&#xff1a; 表格代码如下&#xff1a; <el-table width"100%"ref"tableRef" style"margin-bottom: 15px;":data"jlData"class"tableHeader6"header-row-class-name"headerStyleTr6":row-class-n…

【JavaSE】【网络编程】UDP数据报套接字编程

目录 一、网络编程简介二、Socket套接字三、TCP/UDP简介3.1 有连接 vs 无连接3.2 可靠传输 vs 不可靠传输3.3 面向字节流 vs 面向数据报3.4 双向工 vs 单行工 四、UDP数据报套接字编程4.1 API介绍4.1.1 DatagramSocket类4.1.1.1 构造方法4.1.1.2 主要方法 4.1.2 DatagramPocket…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

【Linux】开发工具make/Makefile、进度条小程序

Linux 1.make/Makefile1.什么是make和Makefile&#xff1f;2.stat命令3.Makefile单个文件的写法4.Makefile多个文件的写法 2.进度条1.回车\r、换行\n2.缓冲区3.进度条1.倒计时程序2.进度条程序 1.make/Makefile 1.什么是make和Makefile&#xff1f; 一个工程中的源文件不计其…

Ubuntu22.04配置强化学习环境及运行相关Demo

什么是强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;简称 RL&#xff09;是机器学习中的一个重要分支&#xff0c;属于一种基于试错机制的学习方法。它通过让智能体&#xff08;Agent&#xff09;与环境&#xff08;Environment&#xff09;进行交互&…

GitHub 开源项目 Puter :云端互联操作系统

每天面对着各种云盘和在线应用&#xff0c;我们常常会遇到这样的困扰。 文件分散在不同平台很难统一管理&#xff0c;付费订阅的软件越来越多&#xff0c;更不用说那些烦人的存储空间限制了。 最近在 GitHub 上发现的一个开源项目 Puter 彻底改变了我的在线办公方式。 让人惊…

深入解析小程序组件:view 和 scroll-view 的基本用法

深入解析小程序组件:view 和 scroll-view 的基本用法 引言 在微信小程序的开发中,组件是构建用户界面的基本单元。两个常用的组件是 view 和 scroll-view。这两个组件不仅功能强大,而且使用灵活,是开发者实现复杂布局和交互的基础。本文将深入探讨这两个组件的基本用法,…