Linux高阶——1110—线程安全问题解决方法

1、同步、异步、阻塞、非阻塞

同步过程:发起调用,调用者需要等待被调用者的结果

异步过程:发起调用,无需等待被调用的结果,当有结果后,此结果传出,无需主动获取

阻塞和非阻塞:发起到产生结果,中间的等待过程

阻塞:放弃cpu

非阻塞:不放弃cpu

2、线程安全问题

1、多线程访问互斥

多线程访问共享数据,引发冲突和异常,例如多个线程操作共享数据结构体,全局变量,磁盘文件等

举例:a=0;a++

a++的操作,汇编指令需要三句:内存取值0,自增1,回写1

当寄存器还未回写成功之前,寄存器中的值仍为0,因此另一个线程在取值时,取到的可能是还未回写成功的1,而是还未自增前的0

结果:多线程访问a,应该是一个累加过程,但是因为访问冲突,导致最终的结果比预期结果小

结果截图:问题不明显,但是有问题

如果中间引入变量,则问题更明显,结果相差更多

解决方法1:互斥锁

1、互斥锁使用目的

互斥锁是用来保护代码段的,一般代码段是用来访问全局变量的

一般只对访问读写全局数据的代码上锁

2、互斥锁的使用范围

上锁与解锁之间的代码,被称为临界区代码,是被互斥保护的

无论有多少线程,临界区代码只允许单独访问,其他线程只能等待

pthread_mutex_t lock

3、互斥锁的性质

多个线程争夺一把锁,利用一把锁来保护代码段,锁具有互斥性,只有一个线程可以使用这把互斥锁, 其余线程需要等待

互斥锁的系统里存在一个等待队列,称为互斥等待队列,进入到等待队列中的线程均为阻塞态

当当前占用锁的线程结束,下一个使用锁的线程确定方式:

1、争夺访问,当锁被解除占用,唤醒所有等待线程,争夺资源

但是可能引起惊群问题:资源有限的情况下,多个线程争夺资源,但是只有少数线程可以获取,那些没有抢到的线程付出的开销没有意义

2、预分配

避免惊群问题,在等待的线程中分配唤醒标记,只有被标记的线程,资源释放后才能被唤醒使用资源

3、就近原则

提高资源的使用效率,如果线程解锁后立即请求,同时满足条件(时间片充裕),依然是此线程占用

4、互斥锁的函数使用

pthread_mutex_t lock——互斥锁类型

lock=PTHREAD_MUTEX_INITIALIZER——静态初始化

pthread_mutex_init(&lock,NULL)——动态初始化

pthread_mutex_destroy(&lock)——释放互斥锁

pthread_mutex_lock(&lock)——上锁请求,阻塞模式下,如果资源被占用,则等待

pthread_mutex_unlock(&lock)——解锁

解决代码

一般习惯将锁设在for循环内部

写端上锁的原因:两个线程同时写入,容易造成相互覆盖

读端上锁的原因:如果一端为读端,一端为写端,可能造成读到的是刚写入的数据

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<pthread.h>
#include<pthread.h>#define FLAG 5000
int a;
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;void * busines(void* arg)
{int tmp;for(int i=0;i<FLAG;i++){   pthread_mutex_lock(&lock);tmp=a;printf("thread 0x%x ++a %d\n",(int)pthread_self,++tmp);a=tmp;pthread_mutex_unlock(&lock);}   
}int main()
{pthread_t tids[2];int i;for(i=0;i<2;i++){   pthread_create(&tids[i],NULL,busines,NULL);}   while(i--){   pthread_join(tids[i],NULL);}   return 0;
}

成功截图

解决方法2:读写锁

1、读写锁的性质

读写锁在互斥锁的基础上修改,它满足多读场景,如果用户要读取数据可以使用读锁访问,如果用户要修改数据使用写锁访问

读共享,写独占,读写互斥

写锁与互斥锁一致,为独占锁

如果要提高资源的读访问效果,可以先采用读写锁,避免使用互斥锁

2、读写锁的函数使用

pthread_rwlock_t lock——读写锁类型

lock=PTHREAD_RWLOCK_INITIALIZER——静态初始化

pthread_rwlock_init(&lock,NULL)——动态初始化

pthread_rwlock_destroy(&lock)——释放锁

pthread_rwlock_rdlock(&lock)——上读锁

pthread_rwlock_wrlock(&lock)——上写锁

pthread_mutex_unlock(&lock)——解锁

读写锁代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<pthread.h>
#include<pthread.h>#define FLAG 5000
int code;
pthread_rwlock_t lock=PTHREAD_RWLOCK_INITIALIZER;void * rd_busines(void* arg)
{while(1){   pthread_rwlock_rdlock(&lock);printf("rd thread 0x%x ,  %d\n",(int)pthread_self(),code);pthread_rwlock_unlock(&lock);usleep(3000000);}   
}void * wr_busines(void* arg)
{while(1){   pthread_rwlock_wrlock(&lock);printf("wr thread 0x%x , ++ %d\n",(int)pthread_self(),++code);pthread_rwlock_unlock(&lock);usleep(3000000);}   
}int main()
{pthread_t tids[8];int i;for(i=0;i<3;i++){pthread_create(&tids[i],NULL,wr_busines,NULL);}for(i=0;i<3;i++){pthread_create(&tids[i],NULL,rd_busines,NULL);}while(i--){pthread_join(tids[i],NULL);}return 0;
}

 成功截图

3、进程可以使用的互斥锁

并发访问冲突不局限于线程,进程也有

进程可以用的互斥锁:根据修改互斥锁属性,将线程变为进程,可以多进程使用,避免访问异常

函数使用

pthread_mutexattr_t attr——互斥锁属性

pthread_mutex_attr_init(&attr)——初始化属性,默认线程锁

pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED)——将互斥锁属性中的锁的状态变为进程锁

pthread_mutexattr_destroy(&attr)——释放互斥锁属性

pthread_mutex_init(&lock,&attr)——初始化锁时使用自定义属性

代码
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<pthread.h>
#include<pthread.h>
#include<sys/mman.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/fcntl.h>typedef struct
{int code;pthread_mutex_t lock;
}shared_t;int main()
{int fd;shared_t* ptr;fd=open("process_map",O_RDWR);ftruncate(fd,sizeof(shared_t));pthread_mutexattr_t attr;pthread_mutexattr_init(&attr);pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);ptr=mmap(NULL,sizeof(shared_t),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);pthread_mutex_init(&ptr->lock,&attr);ptr->code=0;pid_t pid;pid=fork();if(pid>0){for(int i=0;i<5000;i++){pthread_mutex_lock(&ptr->lock);printf("parent %d,++code %d\n",getpid(),++ptr->code);pthread_mutex_unlock(&ptr->lock);}wait(NULL);pthread_mutex_destroy(&ptr->lock);pthread_mutexattr_destroy(&attr);munmap(ptr,sizeof(shared_t));}else if(pid==0){for(int i=0;i<5000;i++){pthread_mutex_lock(&ptr->lock);printf("child %d,++code %d\n",getpid(),++ptr->code);pthread_mutex_unlock(&ptr->lock);}exit(0);}else{perror("fork call failed");exit(0);}return 0;
}
正确截图

2、线程控制与调度线程同步

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

STM32cubemx+Proteus仿真和keil5联合调试

前面两步 STM32cubemx生成代码 https://blog.csdn.net/weixin_52733843/article/details/143637304 Proteus新建工程 https://blog.csdn.net/weixin_52733843/article/details/143578853 1 *Proteus仿真联合调试* 在Proteus中&#xff0c;双击STM32F103C6芯片&#xff0c…

初识算法 · 位运算常见总结(1)

目录 前言&#xff1a; 位运算基本总结 部分题目代码 前言&#xff1a; ​本文的主题是位运算&#xff0c;通过常见的知识点讲解&#xff0c;并且会附上5道简单的题目&#xff0c;5道题目的链接分别为&#xff1a;191. 位1的个数 - 力扣&#xff08;LeetCode&#xff09; 1…

visualvm远程连接Docker容器中部署的java应用并监控

visualvm远程连接Docker容器中部署的java应用 前言 jdk1.8中自带了&#xff0c;java11中需要单独下载 下载地址 visualvm下载地址 简介 java虚拟机监控&#xff0c;故障排查及性能分析工具。 网络配置 局域网与docker内网打通&#xff0c;请参考&#xff1a;办公网络与Docker内…

NVIDIA RTX 系统上使用 llama.cpp 加速 LLM

NVIDIA RTX 系统上使用 llama.cpp 加速 LLM 文章目录 NVIDIA RTX 系统上使用 llama.cpp 加速 LLMllama.cpp 概述llama.cpp 在 NVIDIA RTX 上的加速性能使用 llama.cpp 构建的开发人员生态系统使用 llama.cpp 在 RTX 平台上加速的应用程序开始使用 适用于 Windows PC 的 NVIDIA …

信息收集系列(二):ASN分析及域名收集

内容预览 ≧∀≦ゞ 信息收集系列&#xff08;二&#xff09;&#xff1a;ASN分析及域名收集前言一、ASN 分析1. 获取 ASN 码2. 使用 ASNMap 获取 IP 范围3. 将 IP 范围转化为 IP 列表 二、关联域名收集1. 顶级域&#xff08;TLD&#xff09;收集测试方法 2. 根域名收集常用方法…

揭秘:b站可以通过弹幕查询到发送者吗?答案是:不可行

查找发送者 发弹幕被找到 最近&#xff0c;我的一个好兄弟遇到了这样一个问题&#xff1a;他在b站发弹幕&#xff0c;结果被人找到了。他对此很困惑&#xff1a;“发送弹幕不是匿名的吗&#xff1f;只有评论才能看到用户名啊&#xff0c;难道发弹幕也可以被找到吗&#xff1f…

安装mysql、Navicat 17

1.安装mysql 下载地址 https://downloads.mysql.com/archives/installer/ 选择最新版本或者你需要的版本 点击第二个Download下载 下载完毕后双击启动&#xff0c;之后是这个页面 选Custom&#xff08;第四个&#xff09;自定义安装&#xff0c;可以将mysql安装到自定义目录…

人工智能助手是否让程序员技能退化?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

RecyclerView进阶知识讲解

在 Android 开发中&#xff0c;RecyclerView 是一种高效的列表和网格布局控件&#xff0c;用于显示大规模数据。尽管基本使用方法简单&#xff0c;但深入理解并掌握其高级进阶用法能大幅提升用户体验和应用性能。下面&#xff0c;我将从布局管理、动画和手势、自定义缓存、优化…

测试用例设计方法之判定表

测试用例设计方法之判定表 1. 为什么要有判定表方法2. 什么是判定表3. 判定表法设计用例步骤4. 判定表使用场景 1. 为什么要有判定表方法 案例: 验证"若用户欠费或者关机, 则不允许主被叫"功能的测试 说明: 等价类和边界值分析法主要关注单个输入类条件的测试并未考…

SpringCloud篇(服务拆分 / 远程调用 - 入门案例)

目录 一、服务拆分原则 二、服务拆分示例 1. 案例需求 2. 案例要求 3. 导入SQL语句 4. 实现思路 4.1. 创建父工程 cloud-demo 管理依赖 依赖导入思路 4.2. 创建子工程 order-servic 4.3. 创建子工程 user-servic 4.4. 创建 cloud_order 数据库和表并插入数据 4.5. …

特征融合篇 | YOLO11改进 | 更换上采样方式之轻量级通用上采样算子CARAFE

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。CARAFE算子的主要特点是在保持轻量级功能的同时&#xff0c;能够提供比其他上采样算子更好的性能。它通过少量的参数和计算量来实现高效的图像上采样。CARAFE算子能够根据像素之间的关系进行自适应的上采样&#xff0c;从而…

Java集合Queue——针对实习面试

目录 Java集合QueueQueue接口的特点是什么&#xff1f;Queue和Deque的区别&#xff1f;ArrayDeque和LinkedList的区别&#xff1f;什么是PriorityQueue&#xff1f;什么是BlockingQueue&#xff1f; Java集合Queue Queue接口的特点是什么&#xff1f; Queue接口在Java中是一个…

【支付宝崩了】复盘

一、背景 2024年11月11日&#xff0c;#支付宝崩了#冲上微博热搜第一 部分网友反映支付宝 App无法正常使用&#xff0c;他们遇到了同一笔订单被扣款三次、余额宝转账至余额后余额显示为0、线下支付后商家未收到款项但银行卡已被扣款等问题。 此外&#xff0c;有网友称支付…

丹摩征文活动|FLUX.1+ComfyUI的详细部署以及实验总结

公主请阅 1. FLUX.1的简介2. 部署过程创建资源ComfyUI的部署操作部署FLUX.1 如何使用&#xff1f;实验总结&#xff1a;环境搭建与工具安装实验步骤实验结果分析总结 1. FLUX.1的简介 FLUX.1 是由黑森林实验室开发的图像生成工具&#xff0c;分为三个版本&#xff1a; FLUX-1-…

基于STM32的智能仓库管理系统设计

引言 本项目基于STM32微控制器设计了一个智能仓库管理系统&#xff0c;通过集成多个传感器模块和控制设备&#xff0c;实现对仓库环境和物资管理的自动化监控。该系统能够实时监测仓库内的温湿度、烟雾浓度等参数&#xff0c;并且通过红外传感器监控人员出入&#xff0c;结合R…

206面试题(47~60)

208道Java面试题 47~60 **208道Java面试题****47. 在 Java 程序中怎么保证多线程的运行安全&#xff1f;****48. 多线程中 synchronized 锁升级的原理是什么&#xff1f;****49. 什么是死锁&#xff1f;****50. 怎么防止死锁&#xff1f;****51. ThreadLocal 是什么&#xff1f…

MySQl基础----Linux下数据库的密码和数据库的存储引擎(内附 实操图和手绘图 简单易懂)

绪论​ 涓滴之水可磨损大石&#xff0c;不是由于他力量强大&#xff0c;而是由于昼夜不舍地滴坠。 只有勤奋不懈地努力&#xff0c;才能够获得那些技巧。 ——贝多芬。新开MySQL篇章&#xff0c;本章非常基础&#xff0c;但同时需要一定的Linux基础&#xff0c;所以假若你没学习…

番外篇 | 关于YOLO11算法的改进点总结

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。在2024年9月27日盛大举行的YOLO Vision 2024活动上&#xff0c;Ultralytics公司震撼发布了YOLO系列的最新成员—YOLO11。作为Ultralytics YOLO系列实时目标检测器的最新迭代&#xff0c;YOLO11凭借尖端的准确性、速度和效率…

增长放缓,跨境电商如何以“体验”撬动高转化和高复购?

增长放缓&#xff0c; 跨境电商步入发展新周期 伴随着疫情红利的逐渐收缩&#xff0c;跨境电商市场从野蛮高速增长回归理性&#xff0c;步入新的发展周期&#xff0c;增幅放缓成为新常态。根据eMarketer的统计数据&#xff0c;全球跨境电商销售增长从2020年的26.7%下跌至2022年…