Linux高阶——1110—死锁问题原子访问线程控制与调度线程同步

目录

1、旋转锁

2、死锁问题

死锁问题举例:

1、双线程死锁

 代码

成功截图

2、单线程死锁

死锁问题处理:

死锁问题预防:

有向图

3、原子访问

1、原子访问概念

2、原子访问可用函数

原代码

未加锁代码输出

修改后代码

修改后截图

3、ABA问题

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

例子:两个保安两班倒

使用的函数

代码

成功截图


1、旋转锁

与互斥锁高度相似,一个线程占用资源后,其他线程无法访问

如果是互斥锁会陷入阻塞(放弃cpu)等待,但是自旋锁不阻塞(不放弃cpu),重复申请,直到获取锁为止

一般使用旋转锁时,线程是运行态的

旋转锁的优势:线程使用锁的效率好,一些快速响应的场景比较适合使用旋转锁,但是线程开销比较大,持续占用cpu

2、死锁问题

多线程使用锁时产生死锁,这会导致线程永久阻塞,无法唤醒和继续(卡死)

死锁问题产生的原因:

1、请求与保持        2、互斥访问        3、不可剥夺        4、环形等待

当上述四个必要条件都满足的条件下,死锁才会发生

死锁问题举例:

1、双线程死锁

设置两个变量code1和code2,设置两个线程thread1和thread2

设置一个保护code1的锁lock1,设置一个保护code2的锁lock2

线程thread1的行为为给code1上锁lock1,访问code1,解锁unlock1

死锁问题产生:thread1申请lock1,接着去申请lock2,但是lock2是由thread2已经使用的,thread1会被挂起

此时thread2在已经申请到lock2的情况下,去申请lock1,但此时lock1已经被thread1占用,因此thread2挂起等待

 代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<pthread.h>
#include<pthread.h>int code1;
int code2;
pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2=PTHREAD_MUTEX_INITIALIZER;void * busines_1(void * arg)
{while(1){pthread_mutex_lock(&lock1);sleep(0);printf("thread 0x%x ,output code1  %d\n",(int)pthread_self(),code1);pthread_mutex_lock(&lock2);printf("thread 0x%x ,output code2  %d\n",(int)pthread_self(),code2);pthread_rwlock_unlock(&lock2);pthread_rwlock_unlock(&lock1);}   
}void * busines_2(void * arg)
{while(1){   pthread_mutex_lock(&lock2);sleep(0);printf("thread 0x%x ,output code2  %d\n",(int)pthread_self(),code2);pthread_mutex_lock(&lock1);printf("thread 0x%x ,output code1  %d\n",(int)pthread_self(),code1);pthread_rwlock_unlock(&lock1);pthread_rwlock_unlock(&lock2);}
}int main()
{pthread_t tids[2];int i;for(i=0;i<2;i++){if(i==0)pthread_create(&tids[i],NULL,busines_1,NULL);elsepthread_create(&tids[i],NULL,busines_2,NULL);}while(i--)pthread_join(tids[1],NULL);return 0;
}

成功截图

2、单线程死锁

当某个线程对变量code死锁后,再次对其进行上锁,该进程会被挂起,造成死锁

死锁问题处理:

通过破坏,杀死某个死锁线程来解决死锁问题,但以后需要再次创建,后续依然会产生死锁线程

死锁问题预防:

银行家算法:通过向量进行风险评估的方式,例如:资产集合,5把锁,每次线程申请锁时都要先经过风险评估后,再决定能否获取锁,则能避免死锁问题

有向图

有向图检测,使用图点边,记录线程与资源请求的方向,如果图产生了环,则表示死锁发生

3、原子访问

1、原子访问概念

锁技术虽然可以解决多线程操作资源异常的问题,但是伴随着庞大的开销和时间消耗,尝试无锁编程(原子访问 __sync)避免异常访问

锁的核心为:队列等待        原子问题核心:Compare and Swap

原子访问的最核心问题为(V O N)原则

V=内存当前值        O=旧的预期值        N=新预期值

比较V==O,如果相等,表示没有其他人改变过此值,将新值N赋值给内存当前值V

2、原子访问可用函数

__sync_fetch_and_add(&code,2)——原子加操作

第一个参数:要修改变量的地址        第二个参数:增加的数量        返回值:改变前的值

__sync_add_and_fetch(&code,2)

与__sync_fetch_and_add(&code,2)参数相同,但返回值为修改后的值

__sync_sub_and_fetch()——原子减操作

原子操作一般提供一些关于数值的简单操作,如果操作过于复杂,使用其他的原子函数或无锁编程,比如十个线程访问数据库就不能用原子操作

原代码

#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++){   tmp=a;printf("thread 0x%x ++a %d\n",(int)pthread_self,++tmp);a=tmp;}   
}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;
}

未加锁代码输出

修改后代码

#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;void * busines(void* arg)
{for(int i=0;i<FLAG;i++){   __sync_add_and_fetch(&a,1);printf("thread 0x%x code= %d\n",(int)pthread_self,a);}   
}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;
}

修改后截图

3、ABA问题

为了解决ABA问题,加入版本号进行判断,虽然最后的值与开始预期值相等,也需要查看版本号

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

条件变量技术:若干个线程可以通过判断条件,决定是否执行,如果可执行则完成任务,否则阻塞等待

条件:全局资源        变量:挂起位置与唤醒位置(cond)

默认情况下,多线程执行没有条理和顺序,每个线程使用各自的资源完成各自的任务,让多线程有一个可以判断交汇的场所(全局变量),线程根据变量决定是否执行,实现线程控制协同的目的

条件变量既然是一种协同技术,必然可以进行线程的挂起唤醒控制,不满足执行条件挂起,满足条件唤醒

例子:两个保安两班倒

多个线程工作条件与挂起条件是互补的,所有需要相互唤醒

条件变量的数量取决于执行条件的数量

使用的函数

pthread_cond_t cd;——挂起变量cd

cd=PTHREAD_COND_INITIALLZER

pthread_cond_init(&cd,NULL)

pthread_cond_destroy(&cd)

pthread_cond_wait(&cd,NULL)——调用函数,挂起线程的同时解锁互斥锁,线程被唤醒时再次执行此函数,进行上锁操作

pthread_cond_signal(&cd)——唤醒一个在挂起cd中的线程

pthread_cond_broadcast(&cd)——唤醒所有线程

代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<pthread.h>
#include<pthread.h>int cd1;
pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;int day=0;void* t1(void* arg)
{while(1){   pthread_mutex_lock(&lock);if(day==0)pthread_cond_wait(&cd1,&lock);printf("day ,working...\n");day-=1;pthread_cond_signal(&cd1);pthread_mutex_unlock(&lock);}   
}void* t2(void* arg)
{while(1){   pthread_mutex_lock(&lock);if(day==1)pthread_cond_wait(&cd1,&lock);printf("night ,working...\n");printf("day ,working...\n");day-=1;pthread_cond_signal(&cd1);pthread_mutex_unlock(&lock);}   
}int main()
{pthread_t tids[2];for(int i=0;i<2;i++){if(i==0)pthread_create(&tids[i],NULL,t1,NULL);elsepthread_create(&tids[i],NULL,t2,NULL);}while(1)pthread_join(tids[1],NULL);return 0;
}

成功截图

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

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

相关文章

python入门3

IDE的概念 IDE(Integrated Development Environment)又被称为集成开发环境。说白了&#xff0c;就是有一款图形化界面的软件&#xff0c;它集成了编辑代码&#xff0c;编译代码&#xff0c;分析代码&#xff0c;执行代码以及调试代码等功能。在我们Python开发中&#xff0c;最常…

Ollama—87.4k star 的开源大模型服务框架!!

这一年来&#xff0c;AI 发展的越来越快&#xff0c;大模型使用的门槛也越来越低&#xff0c;每个人都可以在自己的本地运行大模型。今天再给大家介绍一个最厉害的开源大模型服务框架——ollama。 项目介绍 Ollama 是一个开源的大语言模型&#xff08;LLM&#xff09;服务工具…

mysql中的EXISTS和NOT EXISTS使用详解

本文来编写一个实例说下mysql中的EXISTS和NOT EXISTS使用详解 文章目录 exists用法SQL中in, not in, exists, not exists的区别使用实例本文小结 exists用法 exists: 如果括号内子查询语句返回结果不为空&#xff0c;说明where条件成立&#xff0c;就会执行主SQL语句。如果括号…

海量数据去重的哈希与布尔过滤器

目录 散列表 hash与平衡二叉树比较: 散列表组成: hash函数 作用&#xff1a; 怎么选择hash&#xff1a; 选择标准: 常用hash: hash的操作: hash冲突 产生原因 如何描述冲突程度: 解决冲突: 在合理范围内:used < size: 不在合理范围内&#xff08;used > s…

快速掌握——python类 封装[私有属性方法]、继承【python进阶】(内附代码)

1.类的定义 与 实例化对象 在python中使用class关键字创建一个类。 举例子 class Stu(object):id 1001name 张三def __init__(self):passdef fun1(self):pass# 实例化对象 s1 Stu() s2 Stu() print(s1.name) print(s2.name) 第一个方法 __init__是一种特殊的方法&#x…

PO 证书链

提到服务器间证书交换会不会头大,这两天遇到一个B2B接口的通讯证书问题,借机涨姿势,分享之 通常服务器之间通讯证书使用有两种方式: 如果不是生产机,可以简单的使用自签名证书,自签名证书就是下面这两个信息相同,都是自己,工具这里就不介绍了,多的是。双方互换证书,你…

HarmonyOS App 购物助手工具的开发与设计

文章目录 摘要引言功能需求分析技术方案与设计架构设计技术选型 代码示例Demo数据抓取模块数据存储模块历史价格查询和数据可视化模块完整界面布局和调用示例代码详解 QA环节总结参考资料 摘要 随着促销活动的增多&#xff0c;用户面临真假折扣的困惑&#xff0c;特别是在一些…

MPTCP协议

介绍 多路径TCP或 MPTCP协议是标准的扩展传输控制协议并在中进行了描述 RFC 8684号文件它允许设备同时使用多个接口通过单个MPTCP连接发送和接收TCP数据包。MPTCP可以聚合多个接口的带宽&#xff0c;也可以选择延迟最低的接口。它还允许在一条路径断开时进行故障切换&#xff…

1. 初始认识 Spring Cloud

1. 初始认识 Spring Cloud 文章目录 1. 初始认识 Spring Cloud前言2. Spring Cloud 基本介绍3. 系统架构的演变过程3.1 单机架构3.2 动静分离架构&#xff1a;静态缓存 文件存储3.3 分布式架构&#xff1a;业务拆分 负载均衡3.4 微服务架构&#xff1a;使用 Spring Cloud 4. …

网络学习第四篇

引言&#xff1a; 我们在第三篇的时候出现了错误&#xff0c;我们要就行排错&#xff0c;那么我们要知道一下怎么配置静态路由实现ping通&#xff0c;这样子我们才知道下一跳到底是什么&#xff0c;为什么这样子做。 实验目的 理解和掌握静态路由的基本概念和配置方法。 实…

【rf】robotframework自动化测试环境搭建

robotframework自动化测试环境搭建 前言&#xff1a; 1、在2019年之前&#xff0c;robotframework-ride的版本一直是1.5.2.1&#xff0c;是2016年1月份的版本&#xff0c;只能安装在python2.7的环境上&#xff0c;导致如果想同时使用robotframework做测试且又需要python3环境…

opencv入门学习总结

opencv学习总结 不多bb&#xff0c;直接上代码&#xff01;&#xff01;&#xff01; 案例一&#xff1a; import cv2 # 返回当前安装的 OpenCV 库的版本信息 并且是字符串格式 print(cv2.getVersionString()) """ 作用&#xff1a;它可以读取不同格式的图像文…

《DiffusionDet: Diffusion Model for Object Detection》ICCV2023

摘要 本文提出了一种新的框架DiffusionDet&#xff0c;它将目标检测任务表述为从带噪声的边界框到目标边界框的去噪扩散过程&#xff08;如图一所示&#xff09;。在训练阶段&#xff0c;目标边界框逐渐扩散到随机分布&#xff0c;模型学习逆转这一加噪过程。在推理阶段&#…

加深深度学习矩阵计算理解--用人类直觉 走进线性代数(非应试)

文章目录 前言一、向量二、线性组合、空间与基三、矩阵和线性变换四、矩阵乘法与线性变化复合1、矩阵乘法代表线性变换的复合2、实例说明 五、三维空间的线性变换1、基本性质2、直觉理解3、矩阵表示 六、行列式一、行列式的定义2、行列式在空间中的抽象理解 七、逆矩阵 列空间秩…

AIGC学习笔记(5)——AI大模型开发工程师

文章目录 AI大模型开发工程师004 垂直领域的智能在线搜索平台1 智能在线搜索平台需求分析大模型不够“聪明”增强大模型的方式需求分析2 智能在线搜索平台方案设计方案设计技术选型大模型版本GLM-4大模型注册使用Google Cloud平台注册创建可编程的搜索引擎3 智能在线搜索平台代…

【C++滑动窗口】1234. 替换子串得到平衡字符串|1877

本文涉及的基础知识点 C算法&#xff1a;滑动窗口及双指针总结 LeetCode1234. 替换子串得到平衡字符串 有一个只含有 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符&#xff0c;且长度为 n 的字符串。 假如在该字符串中&#xff0c;这四个字符都恰好出现 n/4 次&#xff0c;那么它就…

源码分享-Springboot+Vue大学生社团活动平台附源码,sql文件,配套论文

源码获取: 复制链接到浏览器打开即可领取 夸克网盘领取链接&#xff1a;https://pan.quark.cn/s/187d2ca0e3ec 百度网盘领取链接&#xff1a;https://pan.baidu.com/s/1apbO6k1cEqFXV-USf0I2IA?pwdccaj 提取码: ccaj 1.1课题背景及意义 随着现代网络技术发展&#xff0…

南山前海13元一份的猪脚饭

​今天没有带饭&#xff0c;中午打算去中国国有资本资本风投大厦的工地餐点吃个打工餐。 ​快到工地餐点就看到不少工友已经开始津津有味吃饭了哈。其实树下也有很多小鸟在觅食&#xff0c;可能是找一些剩饭吃的样子&#xff0c;大部分是麻雀为主。​ ​肚子有些饿&#xff0c;…

C++builder中的人工智能(29):如何在Windows项目中导入FANN库

这篇文章旨在使用由Steffen Nissen开发的FANN库实现人工神经网络。FANN库支持20多种编程语言&#xff0c;包括Delphi和C Builder。您可以在FANN的官方网站上找到完整信息和文档&#xff0c;并下载FANN的源文件。 步骤&#xff1a; 下载FANN库&#xff1a; 从Nissen的官方网站下…

Java开发人员学习ArkTs笔记(二)-函数与类

大家好&#xff0c;我是一名热爱Java开发的开发人员。目前&#xff0c;我正在学习ARKTS&#xff08;Advanced Java Knowledge and Technology Stack&#xff09;&#xff0c;并将不断输出我的学习笔记。我将在这里分享我学习ARKTS的过程和心得&#xff0c;希望能够为其他开发人…