Linux锁的使用
一、临界资源与临界区
多线程会共享例如全局变量等资源,我们把会被多个执行流访问的资源称为临界资源,我们是通过代码访问临界资源的,而我们访问临界资源的那部分代码称为临界区。
实现一个抢票系统
只有一个线程抢票时
#include <iostream>
#include <vector>
#include <unistd.h>#include "Thread.hpp"int num = 10000; std::string GetThreadName()
{static int num = 1;char name[64];snprintf(name, sizeof(name), "thread-%d", num++);return name;
}void Ticket(std::string name)
{while(true){if(num > 0){usleep(1000);printf("%s get ticket: %d\n", name.c_str(), num);num--;}else{break;}}
}int main()
{std::string name1 = GetThreadName();Thread<std::string> t1(name1, Ticket, name1);t1.Start();t1.Join();return 0;
}
正常输出,最终票数为0时退出。
但是当我们启动多个线程同时抢票时,num就是临界资源,使用num的那部分代码就是临界区
#include <iostream>
#include <vector>
#include <unistd.h>#include "Thread.hpp"int num = 10000; std::string GetThreadName()
{static int num = 1;char name[64];snprintf(name, sizeof(name), "thread-%d", num++);return name;
}void Ticket(std::string name)
{while(true){if(num > 0){usleep(1000);printf("%s get ticket: %d\n", name.c_str(), num);num--;}else{break;}}
}int main()
{std::string name1 = GetThreadName();Thread<std::string> t1(name1, Ticket, name1);std::string name2 = GetThreadName();Thread<std::string> t2(name2, Ticket, name2);std::string name3 = GetThreadName();Thread<std::string> t3(name3, Ticket, name3);std::string name4 = GetThreadName();Thread<std::string> t4(name4, Ticket, name4);t1.Start();t2.Start();t3.Start();t4.Start();t1.Join();t2.Join();t3.Join();t4.Join();return 0;
}
可以看到出现了0和负数的票数,这是因为当票数只剩1时,有多个执行流在同一时间通过了if判断,使得能继续进行减票操作。
vs下自减操作的反汇编,分为三步:先从内存拿数据,再把数据减1,最后把数据拷贝到内存
多个执行流同时访问临界资源例如自减操作,由于--操作不是原子性的(我们认为一条汇编指令是原子性的,是不会被中断的。但--操作转为汇编指令后,需要多条指令才能完成),当--操作执行到一半切换到其他线程会导致数据不一致的问题。这种情况下需要通过锁把临界区保护起来,每次只让一个执行流访问临界资源,避免数据不一致问题。
互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。
二、使用锁的方法
1.创建锁
如果定义一个全局的锁,直接使用pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER用宏初始化。
如果定义一个局部锁,要使用pthread_mutex_init方法创建,参数attr设为nullptr
2.加锁解锁
使用pthread_mutex_lock加锁,传递锁的地址,
解锁用pthread_mutex_unlock
当我们使用锁后,就能保证每次只有一个执行流能访问临界资源。
#include <iostream>
#include <vector>
#include <unistd.h>#include "Thread.hpp"int num = 10000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义一个全局锁std::string GetThreadName()
{static int num = 1;char name[64];snprintf(name, sizeof(name), "thread-%d", num++);return name;
}void Ticket(std::string name)
{while(true){pthread_mutex_lock(&mutex); //加锁if(num > 0){usleep(1000);printf("%s get ticket: %d\n", name.c_str(), num);num--;pthread_mutex_unlock(&mutex); //解锁}else{pthread_mutex_unlock(&mutex); //解锁break;}}
}int main()
{std::string name1 = GetThreadName();Thread<std::string> t1(name1, Ticket, name1);std::string name2 = GetThreadName();Thread<std::string> t2(name2, Ticket, name2);std::string name3 = GetThreadName();Thread<std::string> t3(name3, Ticket, name3);std::string name4 = GetThreadName();Thread<std::string> t4(name4, Ticket, name4);t1.Start();t2.Start();t3.Start();t4.Start();t1.Join();t2.Join();t3.Join();t4.Join();return 0;
}
结果正常,但是速度慢了很多,因为要不断申请锁和释放锁
加锁解锁的过程是安全的
三、可重入和线程安全
1.概念
线程安全:多个线程并发同一段代码时,不会出现不同的结果。常见对全局变量或者静态变量进行操作, 并且没有锁保护的情况下,会出现该问题。
重入:同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入,我们称之为重入。一个函数在重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入函数,否则,是不可重入函数。
2.常见的线程不安全的情况
1.不保护共享变量的函数
2.函数状态随着被调用,状态发生变化的函数
3.返回指向静态变量指针的函数
4.调用线程不安全函数的函数
3.常见的线程安全的情况
1.调用了malloc/free函数,因为malloc函数是用全局链表来管理堆的
2.调用了标准I/O库函数,标准I/O库的很多实现都以不可重入的方式使用全局数据结构
3.可重入函数体内使用了静态的数据结构
4.常见可重入的情况
1.不使用全局变量或静态变量
2.不使用用malloc或者new开辟出的空间
3.不调用不可重入函数不返回静态或全局数据,所有数据都有函数的调用者提供
4.使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据
5.可重入与线程安全联系
1.函数是可重入的,那就是线程安全的
2.函数是不可重入的,那就不能由多个线程使用,有可能引发线程安全问题
3.如果一个函数中有全局变量,那么这个函数既不是线程安全也不是可重入的。
6.可重入与线程安全区别
1.可重入函数是线程安全函数的一种
2.线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
3.如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生 死锁,因此是不可重入的。
四、死锁
死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。
1.死锁四个必要条件
1.互斥条件:一个资源每次只能被一个执行流使用
2.请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
3.不剥夺条件: 一个执行流已获得的资源,在末使用完之前,不能强行剥夺
4.循环等待条件: 若干执行流之间形成一种头尾相接的循环等待资源的关系
2.避免死锁
1.破坏死锁的四个必要条件
2.加锁顺序一致
3.避免锁未释放的场景
4.资源一次性分配
3.避免死锁算法
1.死锁检测算法
2.银行家算法
一个锁会造成死锁吗?
答案是会的,当一个线程申请完一个锁,访问完临界资源后,接下来该释放锁了,但是代码却写成了加锁,这就会导致死锁问题。
相关文章:

Linux锁的使用
一、临界资源与临界区 多线程会共享例如全局变量等资源,我们把会被多个执行流访问的资源称为临界资源,我们是通过代码访问临界资源的,而我们访问临界资源的那部分代码称为临界区。 实现一个抢票系统 只有一个线程抢票时 #include <ios…...
go语言学习--2.函数
目录 1.函数分类 2.函数的声明和定义 3.函数传参 4.函数返回值 5.递归调用 为完成某一功能的程序指令(语句)的集合,称为函数。 1.函数分类 在Go语言中,函数是第一类对象,我们可以将函数保持到变量中。函数主要有具名和匿名之分&#x…...
[安卓逆向]常见调试和反调试及解决方案
写在前面 我们在逆向软件时难免会遇到一些反调试策略,这篇文章就来详细总结下,现阶段比较流行的几种反调试策略及解决方案。 特定文件检测 反调试功能: 通过检测文件方式,检测android_server文件是否存在设备中的指定目录/data/l…...

uni-app(H5)论坛 | 社区 表情选择 UI组件
项目源码请移步:bbs 效果 实现思路 表情切换 人物、动物、小黄人不同表情之间的切换实际就是组件的切换 emoji表情 emoji表情本身就是一种字符 如需其他emoji表情可参考 EmojiAll中文官方网站 需要注意的就是数据库的存储格式需要支持emoji表情,我项…...

基于SpringBoot+vue的在线商城系统+论文+免费远程调试
基于SpringBootvue的在线商城系统034(含源码 数据库文档免费送) 开发系统:Windows10 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springb…...

mac中创建的证书提示是无效或者是证书不受信任的解决办法
mac中创建的证书提示是无效或者是证书不受信任的解决办法 原因: (1)可能是由于自己的误删除将Apple worldwide Developer Relatioans Certification Authority删除掉了 (2) 由于签发的认证的证书到期了 (3)其它未知原…...

LangChain Demo | 如何调用stackoverflow并结合ReAct回答代码相关问题
背景 楼主决定提升与LLM交互的质量,之前是直接prompt->answer的范式,现在我希望能用上ReAct策略和能够检索StackOverflow,让同一款LLM发挥出更大的作用。 难点 1. 怎样调用StackOverflow step1 pip install stackspi step 2 from la…...

老子云、AMRT3D、眸瑞科技
老子云概述 老子云3D可视化快速开发平台,集云压缩、云烘焙、云存储云展示于一体,使3D模型资源自动输出至移动端PC端、Web端,能在多设备、全平台进行展示和交互,是全球领先、自主可控的自动化3D云引擎。 平台架构 平台特性 1、基…...

2023.4.7 机器学习周报
目录 引言 Abstract 文献阅读 1、题目 2、引言 3、过去方案和Motivation 4、Segment Anything模型 5、创新点 6、实验过程 7、实验结果 1、评价绩效 2、检测评价 3、跟踪评价 8、 结论 总结 引言 本周阅读了一篇关于高效的任意分割模型的文献,用于自…...

如何将平板或手机作为电脑的外接显示器?
先上官网链接:ExtensoDesk 家里有一台华为平板,自从买回来以后除了看视频外,基本没什么作用,于是想着将其作为我电脑的第二个屏幕,提高我学习办公的效率,废物再次利用。最近了解到华为和小米生态有多屏协同…...

Tuxera NTFS for Mac2023绿色免费版 免费的ntfs for mac 免费读写硬盘U盘工具
Tuxera NTFS 2023 Mac免费版是款适合Mac用户使用的磁盘读写工具。Tuxera NTFS 2023 Mac可以很好的帮助用户在Mac上打开、编辑、复制、移动或删除存储在Windows NTFS格式的USB驱动器上的文件。并且Tuxera NTFS 2023 Mac还可以无阻碍地使用各种文件系统磁盘,还能解决磁…...
使用阿里云试用Elasticsearch学习:3.6 处理人类语言——同义词
词干提取是通过简化他们的词根形式来扩大搜索的范围,同义词 通过相关的观念和概念来扩大搜索范围。 也许没有文档匹配查询 “英国女王“ ,但是包含 “英国君主” 的文档可能会被认为是很好的匹配。 用户搜索 “美国” 并且期望找到包含 美利坚合众国 、…...

018——红外遥控模块驱动开发(基于HS0038和I.MX6uLL)
目录 一、 模块介绍 1.1 简介 1.2 协议 二、 驱动代码 三、 应用代码 四、 实验 五、 程序优化 一、 模块介绍 1.1 简介 红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中,像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和…...

【学习心得】Python中的queue模块使用
一、Queue模块的知识点思维导图 二、Queue模块常用函数介绍 queue模块是内置的,不需要安装直接导入就可以了。 (1)创建一个Queue对象 import queue# 创建一个队列实例 q queue.Queue(maxsize20) # 可选参数,默认为无限大&am…...

ubuntu-server部署hive-part4-部署hive
参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本:ubuntu-server-22.04.3 虚拟机:virtualbox7.0 部署hive 下载上传 下载地址 http://archive.apache.org/dist/hive/ apache-hive-3.1.3-bin.tar.gz 以root用户上传至…...

贪心算法|135.分发糖果
力扣题目链接 class Solution { public:int candy(vector<int>& ratings) {vector<int> candyVec(ratings.size(), 1);// 从前向后for (int i 1; i < ratings.size(); i) {if (ratings[i] > ratings[i - 1]) candyVec[i] candyVec[i - 1] 1;}// 从后…...

c# wpf template itemtemplate+ListBox
1.概要 2.代码 <Window x:Class"WpfApp2.Window7"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/…...

关于JVM-三色标记算法剖析
相关系列 深入理解JVM垃圾收集器-CSDN博客 深入理解JVM垃圾收集算法-CSDN博客 深入理解jvm执行引擎-CSDN博客 jvm优化原则-CSDN博客 jvm流程图-CSDN博客 三色标记产生的原因? 在并发标记的过程中,因为标记期间应用线程还在继续跑,对象间的引…...

怎么看有没有装python
windows系统,运行——cmd,进入dos窗口,输入python,安装成功的话可以看到版本信息并进入编程模式。 如下图(我安装的版本是python 3.5.1):...
VS CODE环境安装和hello world
SAP UI5 demo walkthrough tutorial step1 hello word 首先要安装nodejs,然后才能执行下面的操作 nodejs vscode 安装ui5 npm install --global ui5/cli报错解决: idealTree:npm: sill idealTree buildDeps 这个信息说明npm正在构建,如一直停留在这个…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

DeepSeek越强,Kimi越慌?
被DeepSeek吊打的Kimi,还有多少人在用? 去年,月之暗面创始人杨植麟别提有多风光了。90后清华学霸,国产大模型六小虎之一,手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水,单月光是投流就花费2个亿。 疯…...