Linux 第三十四章
🐶博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++,linux
🔥座右铭:“不要等到什么都没有了,才下定决心去做”
🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
封装线程
Linux线程互斥
加锁
创建一个锁(互斥量)
pthread_mutex_lock(&mutex);加锁/pthread_mutex_unlock(&mutex);解锁
源码实现
封装线程
//开发方 #pragma once#include<iostream> #include<string> #include<functional> #include<pthread.h>using namespace std;//typedef function<void()> func_t template<class T>using func_t=function<void(T)>;template<class T>class Thread{ public: Thread(func_t<T> func,const string& threadname,T data):_tid(0),_threadname(threadname),_isrunning(false),_func(func),_data(data) {}static void* Threadroutine(void* args)//类内成员方法,其第一个参数是this指针,所以会导致编译错误//这里使用static,让Thraedroutine成为类的方法, { (void)args;//仅仅是为了消除警告,变量未使用Thread* ts=static_cast<Thread*>(args);ts->_func(ts->_data); return nullptr;}bool Start(){ int n=pthread_create(&_tid,nullptr,Threadroutine,this);//把当前对象传递给线程执行的方法if(n==0) { _isrunning=true; return true;} else return false;}bool Join(){ if(!_isrunning)return true;int n=pthread_join(_tid,nullptr);if(n==0) { _isrunning=false; return true;} return false;}bool Isrunning(){ return _isrunning;}string Threadname(){ return _threadname;} private: pthread_t _tid;string _threadname;bool _isrunning;func_t<T> _func;T _data;};//应用方 #include<iostream> #include"thread.hpp" #include<unistd.h> #include<vector>void Print(int num){ while(num) { cout<<"hello world :"<<num--<<endl; sleep(1); } }string Getthreadname(){ static int number=1;//全局变量char name[64];snprintf(name,sizeof(name),"Thread-%d",number++); return name;}int main(){ //**1** // Thread t(Print,Getthreadname()); // cout<<"is thread running?"<<t.Isrunning()<<endl; // t.Start(); // cout<<"is thread running?"<<t.Isrunning()<<endl; // t.Join();//**2** // const int num=5; // vector<Thread> threads;// for(int i=0;i<num;i++) // { // Thread t(Print,Getthreadname()); // threads.push_back(t); // }// for( auto& thread:threads) // { // cout<<thread.Threadname()<<"is running: "<<thread.Isrunning()<<endl; // }// for(auto& thread:threads) // { // thread.Start(); // }// for( auto& thread:threads) // { // cout<<thread.Threadname()<<"is running: "<<thread.Isrunning()<<endl; // }// //不让主线程退出,让主线程等待子线程 // for( auto& thread:threads) // { // thread.Join(); // }//**3**Thread<int> t(Print,Getthreadname(),10);t.Start(); t.Join();return 0;}Linux线程互斥
1.直接实验?(不确定性高)
多线程抢票的逻辑
抢票系统
Thread-4 get a ticket:0
Thread-1 get a ticket:-1
Thread-2 get a ticket:-2
票被抢到负数是不合理的
2.看到现象—输出概念
1)数据不一致,共享资源(票)
2)任何一个时刻,只允许一个线程正在访问的资源——临界资源(互斥)
3)我们把我们进程中访问临界资源的代码——临界区(被保护起来的重点区域)
4)互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
3.解释问题
int cnt=0;
cnt++;
这种操作不是原子的
抢票中的临界区
抢票中的临界区 int ticket = 10000; void Getticket(string name) { while (true) { if (ticket > 0)//判断ticket也是计算 { usleep(1000); // 模拟抢票的话费时间 printf("%s get a ticket:%d \n", name.c_str(), ticket); ticket—;//在汇编层面,会执行三步 //我的理解:读是在每个线程的上下文数据中,—是在内存中 } else break; } // 实际情况还有后续的动作 }CPU的基本功能
算:算数运算
逻:逻辑运算
中:处理内外中断
控:控制单元
加锁
加锁(牺牲效率为代价的,解决安全性问题)
1.我们要尽可能的给少的代码加锁
2.一般加锁,都是给临界区加锁
根据互斥的定义,任何时刻,只允许一个线程申请锁成功!多个线程申请锁的失败,失败的线程怎么办?在mutex上阻塞,(等待其他线程释放掉锁,再被唤醒申请锁)
申请锁本身是安全的,原子的(只能一个线程申请成功)
一个线程在临界区中访问临界资源的时候,可不可能发生切换?
可能,完全允许,因为该线程被切换,但是没有解锁,其他线程就申请不到锁,只能被阻塞(就不会发生并发访问数据不一致的问题)
创建一个锁(互斥量)
pthread_mutex_t mutex;pthread_mutex_lock(&mutex);加锁/pthread_mutex_unlock(&mutex);解锁
在Linux系统中,pthread_mutex_lock 是一个 POSIX 线程库提供的函数,用于加锁互斥量(mutex)。它的作用是尝试锁定一个互斥量,如果这个互斥量已经被其他线程锁定了,则调用线程会被阻塞直到获取到该互斥量为止。
事例
#include <stdio.h> #include <stdlib.h> #include <pthread.h> pthread_mutex_t mutex;int shared_data = 0;//公共资源void* thread_function(void* arg) {// 加锁pthread_mutex_lock(&mutex);// 访问共享资源shared_data++;printf("Thread ID %ld, shared data: %d\n", pthread_self(), shared_data);// 解锁pthread_mutex_unlock(&mutex);return NULL; }int main() {pthread_t tid1, tid2;// 初始化互斥量if (pthread_mutex_init(&mutex, NULL) != 0) {perror("Mutex initialization failed");exit(EXIT_FAILURE);}// 创建线程pthread_create(&tid1, NULL, thread_function, NULL);pthread_create(&tid2, NULL, thread_function, NULL);// 等待线程结束pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 销毁互斥量pthread_mutex_destroy(&mutex);return 0; } 在上面的示例中,我们首先创建了一个互斥量 pthread_mutex_t mutex,并在主线程中初始化它。然后创建了两个线程,它们会执行 thread_function 函数。在 thread_function 中,通过调用 pthread_mutex_lock 来锁定互斥量,确保对 shared_data 的访问是互斥的,然后进行相应操作,最后再用 pthread_mutex_unlock 解锁。 这样就确保了在任意时刻只有一个线程能够访问 shared_data,避免了数据竞争问题。请注意,对于互斥量的使用需要谨慎处理,以避免死锁等问题。源码实现
main
#include <iostream>#include "thread.hpp"#include <unistd.h>#include <vector>void Print(int num){ while (num){ cout << "hello world :" << num-- << endl;sleep(1); } }string Getthreadname(){ static int number = 1; // 全局变量char name[64];snprintf(name, sizeof(name), "Thread-%d", number++);return name;}int ticket = 10000;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 锁有了,被定义初始化,这是一把全局的锁// 加锁(牺牲效率为代价的,解决安全性问题) // 1.我们要尽可能的给少的代码加锁 // 2.一般加锁,都是给临界区加锁 void Getticket(string name){ while (true){ // 加锁 // 根据互斥的定义,任何时刻,只允许一个线程申请锁成功!多个线程申请锁的失败,失败的线程怎么办?在mutex上阻塞,(等待其他线程释放掉锁,再被唤醒申请锁) pthread_mutex_lock(&mutex); // 申请锁本身是安全的,原子的(只能一个线程申请成功)// 一个线程在临界区中访问临界资源的时候,可不可能发生切换? // 可能,完全允许,因为该线程被切换,但是没有解锁,其他线程就申请不到锁,只能被阻塞 // if (ticket > 0){ usleep(1000); // 模拟抢票的话费时间printf("%s get a ticket:%d \n", name.c_str(), ticket);ticket--; // 解锁 pthread_mutex_unlock(&mutex); } else { // 解锁 pthread_mutex_unlock(&mutex); break; } } // 实际情况还有后续的动作 }int main(){ string name1 = Getthreadname();Thread<string> t1(name1, Getticket, name1);string name2 = Getthreadname();Thread<string> t2(name2, Getticket, name2);string name3 = Getthreadname();Thread<string> t3(name3, Getticket, name3);string name4 = Getthreadname();Thread<string> t4(name4, Getticket, name4);t1.Start(); t2.Start(); t3.Start(); t4.Start();t1.Join(); t2.Join(); t3.Join(); t4.Join(); return 0;}thread.hpp
#pragma once#include<iostream> #include<string> #include<functional> #include<pthread.h>using namespace std;//typedef function<void()> func_t template<class T>using func_t=function<void(T)>;template<class T>class Thread{ public: Thread(const string& threadname,func_t<T> func,T data):_tid(0),_threadname(threadname),_isrunning(false),_func(func),_data(data) {}static void* Threadroutine(void* args)//类内成员方法,其第一个参数是this指针,所以会导致编译错误//这里使用static,让Thraedroutine成为类的方法, { (void)args;//仅仅是为了消除警告,变量未使用Thread* ts=static_cast<Thread*>(args);ts->_func(ts->_data); return nullptr;}bool Start(){ int n=pthread_create(&_tid,nullptr,Threadroutine,this);//把当前对象传递给线程执行的方法if(n==0) { _isrunning=true; return true;} else return false;}bool Join(){ if(!_isrunning)return true;int n=pthread_join(_tid,nullptr);if(n==0) { _isrunning=false; return true;} return false;}bool Isrunning(){ return _isrunning;}string Threadname(){ return _threadname;} private: pthread_t _tid;string _threadname;bool _isrunning;func_t<T> _func;T _data;};进程是资源的分配单位,所以线程并不拥有系统资源,而是共享使用进程的资源,进程的资源由系统进行分配
pthread_self() 用于获取用户态线程的tid,而并非轻量级进程ID主线程调用pthread_cancel(pthread_self())函数来退出自己, 则主线程对应的轻量级进程状态变更成为Z, 其他线程不受影响,这是正确的(正常情况下我们也不会这么做....)
主线程调用pthread_exit只是退出主线程,并不会导致进程的退出
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸
相关文章:
Linux 第三十四章
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…...
国际化日期(inti)
我们可以使用国际化API自动的格式化数字或者日期,并且格式化日期或数字的时候是按照各个国家的习惯来进行格式化的,非常的简单; const now new Date(); labelDate.textContent new Intl.DateTimeFormat(zh-CN).format(now);比如说这是按照…...
【论文阅读笔记】jTrans(ISSTA 22)
个人博客地址 [ISSTA 22] jTrans(个人阅读笔记) 论文:《jTrans: Jump-Aware Transformer for Binary Code Similarity》 仓库:https://github.com/vul337/jTrans 提出的问题 二进制代码相似性检测(BCSD࿰…...
单位个人如何向期刊投稿发表文章?
在单位担任信息宣传员一职以来,我深感肩上的责任重大。每月的对外信息宣传投稿不仅是工作的核心,更是衡量我们部门成效的重要指标。起初,我满腔热血,以为只要勤勉努力,将精心撰写的稿件投至各大报社、报纸期刊的官方邮箱,就能顺利登上版面,赢得读者的青睐。然而,现实远比理想骨…...
Redis数据结构-RedisObject
1.7 Redis数据结构-RedisObject Redis中的任意数据类型的键和值都会被封装为一个RedisObject,也叫做Redis对象,源码如下: 1、什么是redisObject: 从Redis的使用者的角度来看,⼀个Redis节点包含多个databaseÿ…...
Vue 中使用 el-date-picker 限制只能选择当天、当天之前或当天之后日期的方法详解
网上很多都是不完整的,我这里发布一个完整的 - 8.64e7 表示可选择当天时间(注:小于当前时间,- 8.64e7 则是禁用日期不包含当前日,若大于当前日期, 8.64e7 则是禁用日期包含当前日) time.getTi…...
系列介绍:《创意代码:Processing艺术编程之旅》
系列介绍:《创意代码:Processing艺术编程之旅》 标题创意: “代码绘梦:Processing艺术编程入门”“数字画布:用Processing创造视觉奇迹”“编程美学:Processing艺术创作指南”“创意编程:Proc…...
深度学习设计模式之抽象工厂模式
文章目录 前言一、介绍二、详细分析1.核心组成2.实现步骤3.代码示例4.优缺点优点缺点 5.使用场景 总结 前言 本文主要学习抽象工厂模式,抽象工厂模式创建的是对象家族,比如:苹果是一个产品,但是他不单单只生产手机,还…...
K8s是什么?
url address K8s是一个开源的容器编排平台,可以自动化,在部署,管理和扩展容器化应用过程中涉及的许多手动操作。 Kubernetes最初是由Google工程师作为Borg项目开发和设计的,后于2015年捐赠给云原生计算基金会(CNCF&a…...
【网站项目】SpringBoot796水产养殖系统
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
Vue详细介绍
Vue.js(通常简称为Vue)是一个用于构建用户界面的渐进式JavaScript框架。它由尤雨溪(Evan You)创建,并于2014年首次发布。Vue的设计目的是易于上手,同时也能够强大到驱动复杂的单页应用(SPA&…...
声纹识别的对抗与防御
随着机器学习理论和方法的发展, 出现了用于模仿特定说话人语音的深度伪造、针对语音识别和声纹识别的对抗样本, 它们都为破坏语音载体的可信性和安全性提供了具体手段, 进而对各自应用场景的信息安全构成了挑战。 深度伪造是利用生成式对抗网络等方法, 通过构建特定的模型, 产生…...
C++ QT设计模式总结
Ciallo~(∠・ω< )⌒★,这里是 Eureka,欢迎来看我的设计模式总结,有问题随时可以告诉我~ 面向对象的设计模式: 以下总结了面向对象的设计模式, QT 的源码在哪里体现了这些模式,以及如何在 …...
洛谷 P3203:弹飞绵羊 ← 分块算法(单点更新、单点查询)
【题目来源】https://www.acwing.com/problem/content/2168/https://www.luogu.com.cn/problem/P3203【题目描述】 某天,Lostmonkey 发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。 游戏一开始,L…...
程序验证之Dafny--证明霍尔逻辑的半自动化利器
一、What is Dafny?【来自官网介绍 Dafny 】 1)介绍 Dafny 是一种支持验证的编程语言,配备了一个静态程序验证器。 通过将复杂的自动推理与熟悉的编程习语和工具相结合,使开发者能够编写可证明正确的代码(相对于 {P}S{Q} 这种…...
Flutter 中的 SafeArea 小部件:全面指南
Flutter 中的 SafeArea 小部件:全面指南 在移动应用开发中,处理设备屏幕的边缘是一个常见的挑战,尤其是考虑到现代设备通常具有不同的屏幕形状,如刘海屏、曲面屏等。为了确保应用内容不会覆盖这些屏幕区域,Flutter 提…...
webpack生成模块关系依赖图示例:查看构建产物的组成部分 依赖关系图
npm i -D webpack-bundle-analyzer core-js babel-loaderwebpack.config.js const BundleAnalyzerPlugin require(webpack-bundle-analyzer).BundleAnalyzerPlugin; module.exports {entry: ./src/index.js,output: {filename: main.js,},// mode: production, // 或者 produ…...
Spacy的安装与使用教程
官网安装指导教程 https://spacy.io/usage 安装指令 需要根据自己系统的cuda版本选择 nvcc -V pip install -U pip setuptools wheel pip install -U spacy[cuda12x] python -m spacy download zh_core_web_sm python -m spacy download en_core_web_sm...
Pathlib,一个不怕迷路的 Python 向导
大家好!我是爱摸鱼的小鸿,关注我,收看每期的编程干货。 一个简单的库,也许能够开启我们的智慧之门, 一个普通的方法,也许能在危急时刻挽救我们于水深火热, 一个新颖的思维方式,也许能…...
详解绝对路径和相对路径的区别
绝对路径和相对路径是用于描述文件或目录在文件系统中位置的两种不同方式。 绝对路径(Absolute Path)是从文件系统的根目录开始的完整路径,可以唯一地确定一个文件或目录的位置。在不同的操作系统中,根目录的表示方式可能略有不同…...
Android 11 热点永不关闭的三种实现方案:从源码修改到API调用
Android 11热点持久化方案深度解析:从系统底层到应用层的完整实现 在移动设备开发领域,热点功能的稳定性与持久性一直是开发者关注的重点。Android 11系统默认的热点超时机制(10分钟无连接自动关闭)虽然考虑了节能因素,…...
LabVIEW编程整洁之道:提升代码可读性与可维护性的实战技巧
1. 项目概述:从“能用”到“好用”的进阶之路在LabVIEW这个图形化编程环境里摸爬滚打十几年,我见过太多工程师能把功能做出来,但做出来的程序却像一团乱麻——前面板控件堆叠、程序框图连线交错、结构嵌套深不见底。这样的程序,别…...
【亲测免费】 Realtek-RTD2660源代码:开启显示设备定制化的新纪元
Realtek-RTD2660源代码:开启显示设备定制化的新纪元 【下载地址】Realtek-RTD2660源代码源程序 本仓库提供Realtek-RTD2660源代码源程序的下载。该资源文件适用于7至19寸的显示设备,为开发者提供了完整的源代码,方便进行二次开发和定制 项目…...
【亲测免费】 高效便捷的AD域管理Web工具:简化您的域管理流程
高效便捷的AD域管理Web工具:简化您的域管理流程 【下载地址】AD域管理Web版工具 本资源提供了一个基于微软官方文档,使用.NET技术开发的Web AD域管理工具。该工具采用简单的HTML和一般处理程序(Generic Handler)来实现,…...
【亲测免费】 探索卷积神经网络之美:一键绘制专业结构图的利器
探索卷积神经网络之美:一键绘制专业结构图的利器 【下载地址】卷积神经网络结构绘制工具 本资源适用于需要展示卷积神经网络具体结构的研究人员。用户下载本项目后,按照README官方教程中的“Getting Started”部分进行操作,简单学习语法后即可…...
5 分钟快速上手 hoist-non-react-statics:提升组件静态属性的完整教程
5 分钟快速上手 hoist-non-react-statics:提升组件静态属性的完整教程 【免费下载链接】hoist-non-react-statics Copies non-react specific statics from a child component to a parent component 项目地址: https://gitcode.com/gh_mirrors/ho/hoist-non-reac…...
【更新至2025年】2001-2025年上市公司年报文本数据(txt格式)
【更新至2025年】2001-2025年上市公司年报文本数据(txt格式) 1、时间:2001-2025年 2、来源:巨潮资讯网 3、范围:A股上市公司 4、样本量:共7.2W份 5、说明:上市公司年报文本数据可以挖掘文本…...
【Java实战】Java 实现 Base64 文件批量压缩为 ZIP
一、前言在实际项目开发中,经常遇到这样的场景:前端上传多个文件后以 Base64 格式存储,或者从数据库读取多个 Base64 编码的文件,需要将这些文件打包成 ZIP 压缩包供用户下载。本文分享一个实用的 Java ZIP 压缩工具类二、应用场景…...
5分钟搞定Android Studio中文界面:免费汉化插件完整指南
5分钟搞定Android Studio中文界面:免费汉化插件完整指南 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本) 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguagePack 还在为Androi…...
推荐靠谱多模型聚合平台生产厂家,技术扎实服务贴心有保障
随着AI大模型应用场景不断拓展,企业对多模型聚合平台的需求持续攀升。行业报告显示,近一年国内企业采购多模型聚合服务的订单量同比增长超60%,如何选择技术扎实、服务贴心的平台生产厂家,成为企业数字化转型的关键决策。一、技术实…...
