Linux 第三十三章
🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux
🔥座右铭:“不要等到什么都没有了,才下定决心去做”
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
线程
线程控制
pthread_create创建线程
pthread_self
pthread_join
Pthread_exit
pthread_detach
pthread_cancel
系统库调用问题
线程的局部存储
线程
重谈一次地址空间-虚拟到物理的过程
文件系统IO的基本单位大小:4kb
内存以4GB为例,就有1048576个页框(4kb)
struct page
{
int flag;//用于表示该页的状态和属性
//描述一个page的使用情况
//页框的属性
}
为了对所有的页框进行管理,所以需要一个struct page pages[1048576]的数组
线程划分页表的本质:划分地址空间
Int a=100
根据a的虚拟地址,找到a的物理地址,a是一个整形变量,偏移量就位4
在进程视角:虚拟地址本身就是资源!
线程共享进程数据,但也拥有自己的一部分数据:
线程ID 一组寄存器(每个线程有自己的独立上下文数据) 栈 errno 信号屏蔽字 调度优先级
线程控制
pthread_create创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); 这个函数的参数包括:* thread:指向 pthread_t 类型的指针,用于存储新创建线程的标识符。 * attr:指向 pthread_attr_t 类型的指针,用于设置新线程的属性,通常可以设为 NULL 表示使用默认属性。 * start_routine:指向一个函数的指针,该函数定义了新线程要执行的任务。它的签名为 void* func(void*)。 * arg:传递给 start_routine 函数的参数。//对象/结构体linux下有没有真正的线程?
没有。只有轻量级进程的概念,所以linux os只会提供轻量级进程创建的系统调用,不会直接提供线程创建接口
所以需要一个库pthread,这个库不属于c/c++,这个库是操作系统自带的,编译时链接我们的库
function<void()> 是 C++11 中引入的函数对象,它可以用来表示一个没有参数且没有返回值的函数。在 C++ 中,函数对象是可调用的实体,类似于函数指针,但具有更大的灵活性和功能。
事例
#include <iostream> #include <pthread.h> #include <string> #include <unistd.h> #include <functional> #include <time.h> #include <vector>using namespace std;const int threadnum = 5; using func_t = function<void()>;class threaddata { public: threaddata(const string &name, const uint64_t &time, func_t f): threadname(name), createtime(time), func(f){ }public: string threadname;uint64_t createtime;func_t func;};void print(){ cout << "我是线程执行的大任务的一部分" << endl;}// 新线程 void *ThreadRountine(void *args){ threaddata *td = static_cast<threaddata *>(args); // 安全强转threaddata*类型while (true){ cout << "new thread"<< " thread name:" << td->threadname << " thread time:" << td->createtime << endl;td->func(); sleep(1);//测试一个线程异常,整个进程就结束了 // int a=10; // if(td->threadname=="thread-4") // { // cout<<"触发异常"<<endl; // a/=0; // } } }// 如何给新线程传参,如何创建多线程呢 // 获取返回值// 主线程 int main(){ vector<pthread_t> pthreads;for (int i = 0; i < threadnum; i++){ char pthreadname[64];snprintf(pthreadname, sizeof(pthreadname), "%s-%lu", "thread", i);pthread_t tid;threaddata *td = new threaddata(pthreadname, (uint64_t)time(nullptr), print);pthread_create(&tid, nullptr, ThreadRountine, td);pthreads.push_back(tid); sleep(1); }while (true){ cout << "main thread" << endl;sleep(3); } return 0;}pthread_self
在Linux中,
pthread_self函数用于获取当前线程的线程ID(pthread_t)。它的声明如下:
#include <pthread.h>pthread_t pthread_self(void);调用
pthread_self函数将返回当前线程的线程ID,即pthread_t类型的值。线程ID 是一个唯一标识符,用于区分不同的线程。通常情况下,你可以将线程ID存储在变量中以供后续使用。线程终止
1. 新线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
2. 线程可以调用pthread_exit终止自己。
3. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。
线程默认要被等待
1.线程退出,没有等待,会导致类似进程的僵尸问题
2.线程退出时,主线程如何获取新线程的返回值!
pthread_join
pthread_join 是 POSIX 线程库中的函数,用于等待指定的线程结束执行。它会阻塞当前线程,直到指定的线程完成为止。
int pthread_join(pthread_t thread, void **retval); * thread:要等待的线程的线程 ID。 * retval:指向指针的指针,用于接收被等待线程的返回值(如果有)。事例
#include <stdio.h> #include <pthread.h> void* threadFunction(void* arg) {printf("Inside the new thread\n");return (void*)42; } int main() {pthread_t thread;pthread_create(&thread, NULL, threadFunction, NULL); // 创建一个新线程// 等待新线程结束void* result;pthread_join(thread, &result);printf("New thread returned: %ld\n", (long)result);return 0; } 在这个示例中,我们创建了一个新线程,并在主线程中调用 pthread_join 来等待新线程结束。pthread_join 函数会将主线程阻塞直到新线程执行结束, 并且可以获取新线程的返回值。需要注意的是,pthread_join 函数会阻塞当前线程,直到指定的线程结束。因此,在实际使用中,需要确保调用 pthread_join 的线程不是主要的执行线程,否则可能会导致整个程序被阻塞。
Pthread_exit
pthread_exit函数用于终止调用它的线程。当线程调用pthread_exit时,它会立即退出,而不会影响其他线程的执行。线程在退出时可以返回一个指向线程退出状态的指针。
例:
pthread_exit((void*)"thread_1 done");如果线程退出出现异常呢?
如果线程出现异常,整个进程都会崩溃,所以没必要获取线程退出信号
线程的返回值,不一定返回的都是字符串,还可以是对象
线程没有非阻塞等待,线程等待很极端,要么一直等,要么不等
线程默认是:线程模式joinable的(是可以被等待的)
线程是可以被设置为分离状态的
在线程设置为分离状态后,该线程结束时系统会自动释放其所占用的资源,而不需要其他线程调用pthread_join来回收资源
pthread_detach
使用 pthread_detach 函数可以避免出现僵尸线程,提高系统效率。要使用 pthread_detach 函数,首先需要创建线程,并在创建后立即使用 pthread_detach 函数将线程设置为分离状态。
主线程可以调用pthread_detach分离新线程
新线程也可以调用pthread_detach分离自己
pthread_cancel
线程取消
Pthread_cancel(tid);
线程如果是分离的,是可以被取消的,但是不可以被等待
如果线程是被取消的,线程返回的值是-1,
全部都不是系统直接提供的接口,而是原生线程库pthread(默认是os自带的)提供的接口
linux中的线程被叫作用户级线程
系统库调用问题
线程要有独立属性
1)硬件上下文
2)栈:
新线程的栈,在库维护
默认地址空间中的栈,由主线程使用
clone 是一个系统调用,用于创建一个新的进程或线程。与 fork 系统调用不同的是,clone 允许创建的新进程或线程与父进程或线程共享某些资源,如内存空间、文件描述符等,从而实现更灵活的进程/线程管理。
clone 的原型如下:
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
其中参数含义如下:
* fn:指向新进程/线程执行的函数指针
* child_stack:指向新进程/线程栈的指针
* flags:用于指定创建新进程/线程的标志
* arg:传递给新进程/线程执行函数的参数
clone 的常用标志包括:
* CLONE_VM:共享内存空间
* CLONE_FS:共享文件系统信息
* CLONE_FILES:共享文件描述符
* CLONE_SIGHAND:共享信号处理器
线程库不仅要管理每个线程tcb,还要提供一些方法(pthread_create/pthread_join,pthread_cancel/pthread_self)
线程的局部存储
在 C/C++ 中,__thread 是一种线程局部存储(Thread-Local Storage,TLS)的实现方式,用于声明线程私有变量。在使用 __thread 关键字声明的变量中,每个线程都会有自己独立的变量副本,不同线程之间互不影响。
__thread int g_val=100;//线程的局部存储
g_val 被声明为一个 __thread 变量,其初始值为 100。这意味着每个线程都会有一个名为 g_val 的变量,且其初始值为 100。不同线程中对 g_val 的操作都是互相独立的,一个线程修改 g_val 的值不会影响到其他线程中 g_val 的值。
线程可以进行fork?线程可以进行exec*程序替换吗?
可以fork,就是整个进程创建了一个子进程
程序替换之后,整个进程会被替换,所以建议,线程直接程序替换
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸
相关文章:
Linux 第三十三章
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…...
低空经济:无人机竞赛详解
无人机竞赛市场近年来呈现出蓬勃发展的态势,其市场价值不仅体现在竞赛本身,还体现在推动无人机技术创新、拓展应用场景以及促进产业链发展等多个方面。 一、比赛项目介绍 无人机竞赛通常分为多个项目,包括竞速赛、技巧赛、航拍赛等。每个项目…...
CAD插入文字到另一图形样式变相同
CAD从一张图形复制到另外一张图形后,文字样式变成一样是因为两张图所用的文字样式名称一样,但是样式里面的使用字体样式不一样。如下图所示,找到工具栏中的注释 ,点击文字样式。里面就会显示当前图形中使用的样式名称及其对应的字…...
算法随想录第八天打卡|344.反转字符串,541. 反转字符串II, 卡码网:54.替换数字, 151.翻转字符串里的单词,卡码网:55.右旋转字符串
344.反转字符串 建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数 题目链接/文章讲解/视频讲解:代码随想录 Python class Solution:def reve…...
外卖系统的JWT实现登录
1、什么是JWT jwt可以生成一个加密的token,作为用户登录的令牌,当用户登陆成功之后,发放给客户端。请求需要登录的资源或者接口的时候,将token携带,后端验证token是否合法。jwt有三部分组成: A:…...
基于springboot实现的家具销售电商平台
开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包&…...
STM32中的Systick的使用
SysTick,全称System Tick Timer,是Cortex-M microcontrollers内核中提供的一个简单而有效的系统定时器,设计用来给操作系统提供时间基准,或用于生成周期性的中断。STM32系列微控制器,作为基于ARM Cortex-M内核的设备&a…...
做一个桌面悬浮翻页时钟
毛玻璃效果翻页桌面悬浮时钟,TopMost(Topmost“True”),不在任务栏显示(ShowInTaskbar“False”),在托盘区显示图标,双击托盘区图标实现最小化和还原,右键托盘图标可选“…...
Transformers中加载预训练模型的过程剖析(一)
使用HuggingFace的Transformers库加载预训练模型来处理下游深度学习任务很是方便,然而加载预训练模型的方法多种多样且过程比较隐蔽,这在一定程度上会给人带来困惑。因此,本篇文章主要讲一下使用不同方法加载本地预训练模型的区别、加载预训练模型及其配置的过程,藉此做个记…...
数据可视化的艺术:使用Matplotlib和Seaborn揭示数据故事
引言 数据可视化是数据分析中的关键一环,它帮助我们理解数据模式、趋势和异常。在Python中,Matplotlib和Seaborn是两个流行的数据可视化库,它们提供了丰富的图表和图形选项,使数据的可视化变得简单而强大。 Matplotlibÿ…...
2024全新小狐狸AI免授权源码
源码安装说明: 下 载 地 址 : runruncode.com/php/19757.html 1. 在宝塔新建一个站点,选择 PHP 版本为 7.2、7.3 或 7.4。将压缩包上传到站点的根目录,并设置运行目录为 /public。 2. 导入数据库文件,该文件位于 …...
Python基础详解四
目录 一,Json解析 二,pyecharts模块 三,类和对象 四,类型注解 一,Json解析 字典转换为JSON: import jsondata [{"name":"袁震","age":20},{"name":"张三&…...
es6新语法和ajax和json
es6新语法 1.定义变量:let 2.定义常量:const <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…...
Hadoop3:HDFS副本节点选择逻辑讲解
一、副本节点选择(机架感知) 说明 第一个副本,因为我们的client可能是web页,也可能是shell终端。 如果是web页,则随机选取一个节点,如果是shell终端,则选择当前shell终端所在的节点。 节点距离最…...
Java 高级面试问题及答案 更新(二)
Java 高级面试问题及答案 以下是几个常见的Java高级面试问题及其答案,这些问题覆盖了Java语言的核心概念和高级特性。 问题1: 什么是Java内存模型(JMM),它在并发编程中扮演着什么角色? 答案: Java内存模型(JMM)是一个抽象的概念…...
MacOS安装Go
下载 Go 安装包: 访问 Go 官方网站的下载页面,找到适合 macOS 系统的 Go 安装包,并下载 go1.20.2.darwin-amd64.pkg(假设你的 macOS 是 64 位系统)。 安装 Go: 打开下载的安装包 go1.20.2.darwin-amd64.pk…...
【微服务最全详解】
文章目录 微服务微服务的介绍微服务服务架构演变 微服务网关微服务的负载均衡微服务的容灾机制服务崩溃服务容灾机制微服务熔断机制微服务限流Sentinel怎么实现限流微服务限流算法1.令牌桶算法2.漏斗桶算法 服务监控日志收集 微服务 微服务的介绍 微服务是一种软件架构风格&a…...
如何在云电脑实现虚拟应用—数据分层(应用分层)技术简介
数据分层(应用分层)技术简介 近几年虚拟化市场实现了非常大的发展,桌面虚拟化在企业中应用越来越广泛,其拥有的如下优点得到大量企业的青睐: 数据安全不落地。在虚拟化环境下面数据保存在中心服务器上面,…...
【动态规划五】回文串问题
目录 leetcode题目 一、回文子串 二、最长回文子串 三、分割回文串 IV 四、分割回文串 II 五、最长回文子序列 六、让字符串成为回文串的最少插入次数 leetcode题目 一、回文子串 647. 回文子串 - 力扣(LeetCode)https://leetcode.cn/problems/…...
【C++杂货铺铺】AVL树
目录 🌈前言🌈 📁 概念 📁 节点的定义 📁 插入 📁 旋转 1 . 新节点插入较高左子树的左侧---左左:右单旋 2. 新节点插入较高右子树的右侧---右右:左单旋 3. 新节点插入较高左…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...


