多线程(如何理解pthread库)

上一节,我们主要介绍了pthread库中一些常见函数的用法,这节我们主要分析一下pthread库到底是什么?

什么是库

我们之前提过,在每一个linux平台下,必定会存在对应的pthread库
它存在于/lib64这个路径底下
在这里插入图片描述
换句话说,库的本质其实就是文件
既然是文件,按照我们之前动态库的知识,我们知道,它需要从磁盘,加载到内存之中,再根据页表,映射到对应的共享区
由于我们不同的执行流,共享的是同一个虚拟地址,因此,同一进程的不同线程都可以随时访问库中的代码和数据
在库中的代码,就有包含诸如线程管理的操作,通过这种方式,我们就可以实现对应的线程切换的操作
具体如何切换呢?
先描述再组织
先描述一个线程,再将不同描述好的线程组织起来,才考虑切换的问题

LWP和TCB

和文件系统类似,在内核级别,我们存在一个file的结构体,并通过数组的方式(文件描述符),对这些结构体进行管理
但是我们进行的操作,都是对struct FIL(C语言),或者fstream对象(C++)进行操作
这是因为操作系统并不信任用户,假如放开权限,让用户自己进行管理,一是所耗费的成本实在是太大了,学习系统级别的操作并不容易;二是极度不安全,用户随随便便不合适的操作就可能导致操作系统的崩溃
因此,我们所学习的操作,都是建立在这之上的,语言级别的操作函数,它的底层会调用相应的诸如open等等系统接口函数
无独有偶
我们之前提到过,在linux系统下,并没有真线程的概念
只有赋用进程结构的轻量级进程LWP
LWP就类似于我们内核中的struct file结构体,我们用户是不能直接操作的
真正的系统调用接口函数是诸如clone这样的函数
在这里插入图片描述

linux开发者在这之上,开发了pthread库,通过调用pthread库里面的函数(桥梁),在用户层,我们就可以进行线程的管理;而在操作系统眼里,我们就会调用相应的clone系统调用接口,对轻量级线程LWP进行操作
那在语言层面上进行类比,也应该有类似struct FILE结构体一样的存在
答案是也存在的!
在虚拟内存中(语言层面),我们在共享区会存在对应的struct pthread结构体,我们把它称之为TCB(用户级线程)
在这里插入图片描述

至此,我们就初步实现了描述一个线程
在TCB中,存有对应线程的属性,其中就包括我们先前提到的joinable属性,还有每个线程都存在的自己的独立栈空间等等

线程ID

那如何管理不同的线程呢?
文件系统采用的是文件描述符,以数组的方式进行管理,对应的下标就是文件描述符
线程采取的也是类似的方法
不同的线程经过描述后,其实是挨在一起的,就像一个"数组"一样.
因此我们要找到一个用户级线程,实际上,只需要找到该线程内存块的起始地址,然后就可以获取到该线程的各种信息

所谓的线程ID,就是一个地址数据!!!
它用来标识线程相关属性集合(TCB)的起始地址
更进一步来说,就是偏移地址,通过线程ID,我们就能访问不同的线程TCB!
在这里插入图片描述

独立栈与线程局部存储

在这之前,我们已经验证过,不同的线程,拥有自己的独立栈
假如每个线程都创建一个cnt变量,并在每次循环的时候,进行对应的减减操作,此时虽然变量名是相同的,但是它们并不是同一个变量

    1 #include <iostream>2 #include <pthread.h>3 #include <unistd.h>4 #include <cstring>5 #include <string>6 using namespace std;7 8 int g_val =100;9 string toHex(pthread_t tid)10 {11   char buffer[64];12   snprintf(buffer,64,"0x%x",tid);13   return buffer;14 }15 void* pthreadRun(void* args)16 {17   string name = static_cast<const char*>(args);18   int cnt = 5;19   while(cnt)20   {21     cout << name << " : " << cnt-- << ",cnt: " << cnt << endl;                                                                                                    22     //cout << name << " g_val: " << g_val++ << ", &g_val: " << &g_val << endl;23     sleep(1);24   }25   return nullptr;26 }27 int main()28 {29   pthread_t t1,t2,t3;30   pthread_create(&t1,nullptr,pthreadRun,(void*)"thread 1");31   pthread_create(&t2,nullptr,pthreadRun,(void*)"thread 2");32   pthread_create(&t3,nullptr,pthreadRun,(void*)"thread 3");33 34   pthread_join(t1,nullptr);35   pthread_join(t2,nullptr);36   pthread_join(t3,nullptr);37   return 0;38 }

从输出的结果也可以验证这一点,每个不同的cnt都会进行减1操作
若是相同的cnt,三个线程同时进行减1操作,则很快就会减为0
在这里插入图片描述
而cnt在函数内部,是一个临时变量
也侧面印证了我们所有线程都有自己独立的栈结构的观点
那我们原来说的虚拟地址空间中的栈又是什么呢?
之前我们的说法针对的都是拥有一个执行流的进程
现在也是一样,只不过是多个执行流
因此,我们之前所说的,虚拟地址空间中的栈,是进程系统栈,是主线程用的;而新线程用的是库中的栈
其中,下面的这些数据,都是每个线程自己独立拥有的

线程ID
一组寄存器

errno
信号屏蔽字
调度优先级

更深层次讲,为什么每个线程能够自由的切换不同的栈呢?

原因就在于每个线程都有自己独立的一组寄存器,进入函数,实际就是创建对应的函数栈帧,只要更改ebp,esp,我们就能切换线程的栈

C++线程库

这里并不是讲解C++线程库是如何使用的
而是指出,在使用C++线程库的时候,也需要包含pthread.h头文件
假如不包相应的头文件,则g++编译的时候,就会发生报错
原因就在于C++thread库的实现,其实就是对我们上述讲的对原生线程库的封装,使用户实现多线程更为便捷
而在使用的时候,我们也是多学习有关语言层次的线程库使用,而比较少用原生线程库
原因就在于,语言是可以跨平台实现的,在封装的时候,就已经充分考虑过平台问题,一段相同的代码,既可以在linux上跑,也可以在windows上跑;但是原生线程库,只适用于Linux系统

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

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

相关文章

辅助驾驶功能开发-测试篇(2)-真值系统介绍

1 真值系统概述 1.1 真值评测系统核心应用 快速构建有效感知真值,快速完成感知性能评估,快速分析感知性能缺陷。 主要应用场景包括: 1. 感知算法开发验证: 在算法开发周期中,评测结果可以作为测试报告的一部分,体现算法性能的提升。 2. 遴选供应…

我的企业证书是正常的但是下载应用app到手机提示无法安装“app名字”无法安装此app,因为无法验证其完整性解决方案

我的企业证书是正常的但是下载应用app到手机提示无法安装“app名字”无法安装此app&#xff0c;因为无法验证其完整性解决方案 首先&#xff0c;确保您从可信任的来源下载并安装企业开发者签名过的应用程序。如果您不确定应用程序的来源&#xff0c;建议您联系应用程序提供者…

linux下查找文件的相关命令

linux下查找文件的相关命令 运行环境&#xff1a;centos7 参考来源&#xff1a;man、鸟哥入门书籍 一、脚本文件查找&#xff1a;which/type 1. which man手册描述&#xff1a; 返回当前环境可以被执行的文件&#xff08;或链接&#xff09;的路径。搜索PATH变量匹配参数中…

【PostgreSQL】【存储管理】表和元组的组织方式

外存管理负责处理数据库与外存介质(PostgreSQL8.4.1版本中只支持磁盘的管理操作)的交互过程。在PostgreSQL中&#xff0c;外存管理由SMGR(主要代码在smgr.c中)提供了对外存的统一接口。SMGR负责统管各种介质管理器&#xff0c;会根据上层的请求选择一个具体的介质管理器进行操作…

十四天学会C++之第二天(函数和库)

1. 函数的定义和调用 在C中&#xff0c;函数是组织和结构化代码的关键工具之一。它们允许您将一段代码封装成一个可重复使用的模块&#xff0c;这有助于提高代码的可读性和维护性。 为什么使用函数&#xff1f; 函数在编程中的作用不可小觑。它们有以下几个重要用途&#xf…

WEB3 solidity 带着大家编写测试代码 操作订单 创建/取消/填充操作

好 在我们的不懈努力之下 交易所中的三种订单函数已经写出来了 但是 我们只是编译 确认了 代码没什么问题 但还没有实际的测试过 这个测试做起来 其实就比较的麻烦了 首先要有两个账号 且他们都要在交易所中有存入 我们还是先将 ganache 的虚拟环境启动起来 然后 我们在项目…

EasyX图形库note4,动画及键盘交互

大家好&#xff0c;这里是Dark Flame Master&#xff0c;专栏从这篇开始就会变得很有意思&#xff0c;我们可以利用今天所学的只是实现很多功能&#xff0c;同样为之后的更加好玩的内容打下基础&#xff0c;从这届开始将会利用所学的知识制作一些小游戏&#xff0c;废话不多说&…

第一百六十二回 PopupMenuButton组件

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了Sliver综合示例相关的内容&#xff0c;本章回中将介绍 PopupMenuButton组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的PopupMenuButton组件位于AppBar右侧&#xff0c;通常显…

MacOS怎么安装Nacos(附带:Windows系统)

MacOS安装Nacos&#xff08;一定要配置JDK的环境变量&#xff0c;后面告诉你为什么&#xff1f;&#xff09; &#xff08;1&#xff09;进入Nacos官网&#xff0c;前往githubhomehomehttp://nacos.io/zh-cn/ &#xff08;2&#xff09;点击右下角的releases 然后点击Tags 选择…

Linux实用操作(固定IP、进程控制、监控、文件解压缩)

目录 一、快捷键 1、ctrl c强制停止 2、ctrl d退出或登出 3、历史命令搜索history 4、光标移动快捷键 5、清屏 二、软件安装 1、CentOS的yum命令 2、Ubantu的apt命令 三、systemctl命令 四、软连接 五、日期、时区 1、date命令 2、修改Linux时区为东八区 3、nt…

智慧公厕整体解决方案,厕所革命实施方案的范本

随着城市化进程的不断加快&#xff0c;智慧城市应用正成为未来城市发展的重要方向。其中&#xff0c;智慧公厕作为城市基础设施的重要组成部分&#xff0c;其建设范本已经成为各建设中的智慧城市不可或缺的重要内容。那么&#xff0c;如何打造智慧公厕整体解决方案&#xff1f;…

servlet 线程模型 异步

在 servlet 3.0 之前&#xff0c;请求与线程的对应关系是1:1&#xff0c;对应jvm与操作系统的线程的关系。 servlet 3.0 https://jcp.org/en/jsr/detail?id315 从 servlet 3.0 开始&#xff0c;开始有了异步相关功能&#xff0c;作为 Java EE 6 的新功能。 容器线程池与业务线…

王杰国庆作业day6

服务器 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <my_head.h> #define PORT 2324 //端口号 #define IP "192.168.10.107" //本机IP int main(int argc, const char *argv[]) {sqlite3* d…

宠物医院必备,介绍一款宠物疫苗接种管理软件

在当今社会&#xff0c;养宠物已经成为越来越多人的生活方式&#xff0c;宠物疫苗接种已是宠物医院的重要工作&#xff0c;但是目前绝大多数的宠物医院对疫苗接种的管理&#xff0c;还是采取人工登记方式&#xff0c;不仅效率低下&#xff0c;而且无法做到疫苗接种到期自动提醒…

【Vim 插件管理器】Vim-plug和Vim-vbundle的区别

- vundle是一款老款的插件管理工具 - vim-plug相对较新&#xff0c;特点是支持异步加载&#xff0c;相比vundle而言 Vim-plug 是一个自由、开源、速度非常快的、极简的 vim 插件管理器。它可以并行地安装或更新插件。你还可以回滚更新。它创建浅层克隆shallow clone最小化磁盘…

【算法训练-二分查找 一】二分查找、在排序数组中查找元素的第一个和最后一个位置

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是螺旋矩阵&#xff0c;使用【二维数组】这个基本的数据结构来实现 二分查找【EASY】 从最简单的二分查找入手&#xff0c;进而开始解决一系列其变体…

BASH shell脚本篇3——字符串处理

这篇文章介绍下BASH shell中的字符串处理的相关命令。之前有介绍过shell的其它命令&#xff0c;请参考&#xff1a; BASH shell脚本篇1——基本命令 BASH shell脚本篇2——条件命令 Bash字符串也是一种数据类型&#xff0c;它用于表示文本而不是数字&#xff0c;它是一组可能…

哈哈,我保研985了,之后会出一期保研经验分享

哈哈&#xff0c;我保研了&#xff0c;之后会出一期保研经验分享 个人背景 学校&#xff1a;河南某四非&#xff0c;计算机科学与技术专业英语成绩&#xff1a;四级439&#xff0c;六级438&#xff08;夏令营无六级&#xff09;科研经历&#xff1a;一个软著、国家级大创&…

软件测试教程 自动化测试selenium篇(二)

掌握Selenium常用的API的使用 一、webdriver API public class Main {public static void main(String[] args) {ChromeOptions options=new ChromeOptions();//参数表示允许所有请求options.addArguments("--remote-allow-origins=*");WebDriver webDriver=new Chr…

基于被囊群优化的BP神经网络(分类应用) - 附代码

基于被囊群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于被囊群优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.被囊群优化BP神经网络3.1 BP神经网络参数设置3.2 被囊群算法应用 4.测试结果&#x…