Linux-线程互斥和死锁

目录

一.线程互斥

1.1 进程线程间的互斥相关背景概念

1.2 互斥量mutex

二.互斥量的接口

2.1 初始化互斥量

2.2 销毁互斥量

2.3 互斥量加锁和解锁

2.4 改进后售票代码

三.死锁

3.1.什么是死锁?

3.2.死锁四个必要条件

3.3 避免死锁


一.线程互斥

1.1 进程线程间的互斥相关背景概念

  • 临界资源:多线程执行流共享的资源就叫做临界资源
  • 临界区:每个线程内部,访问临界区的代码,就叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成

1.2 互斥量mutex

  • 大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况,变量归属单个 线程,其他线程无法获得这种变量。
  • 但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之 间的交互。
  • 多个线程并发的操作共享变量,会带来一些问题。
// 操作共享变量会有问题的售票系统代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int ticket = 100;
void *route(void *arg)
{char *id = (char *)arg;while (1){if (ticket > 0){usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;}else{break;}}
}
int main(void)
{pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, "thread 1");pthread_create(&t2, NULL, route, "thread 2");pthread_create(&t3, NULL, route, "thread 3");pthread_create(&t4, NULL, route, "thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);
}

为什么结果会到负数?

  1. if 语句判断条件为真以后,代码可以并发的切换到其他线程
  2. usleep这个模拟漫长业务的过程,在这个漫长的业务过程中,可能有很多个线程会进入该代码段
  3. --ticket操作本身就不是一个原子操作
--操作的汇编代码
152 40064b: 8b 05 e3 04 20 00 mov 0x2004e3(%rip),%eax # 600b34 <ticket>
153 400651: 83 e8 01 sub $0x1,%eax
154 400654: 89 05 da 04 20 00 mov %eax,0x2004da(%rip) # 600b34 <ticket>

--操作并不是原子操作,而是对应三条汇编指令:

  1. 将共享变量ticket从内存加载到寄存器中
  2. 更新寄存器里面的值,执行-1操作
  3. 将新值,从寄存器写回共享变量ticket的内存地址

要解决以上问题,需要做到三点:

  1. 代码必须要有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
  2. 如果多个线程同时要求执行临界区的代码,并且临界区没有线程在执行,那么只能允许一个线程进入该临 界区。
  3. 如果线程不在临界区中执行,那么该线程不能阻止其他线程进入临界区。

要做到这三点,本质上就是需要一把锁。Linux上提供的这把锁叫互斥量。

二.互斥量的接口

2.1 初始化互斥量

   Linux下

//静态分配
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER//动态分配
pthread_mutex_t mutex;
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t
*restrict attr);参数:
mutex:要初始化的互斥量
attr:NULL

 C++(默认构造 创建的时候就初始化了)

std::mutex mu;

2.2 销毁互斥量

销毁互斥量需要注意:

  • 不要销毁一个已经加锁的互斥量
  • 使用PTHREAD_ MUTEX_ INITIALIZER初始化的互斥量不需要销毁
  • 已经销毁的互斥量,要确保后面不会有线程再尝试加锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);

在C++中,使用 <mutex> 标准库时,std::mutex 对象的销毁会自动发生,通常不需要手动干预。当 std::mutex 对象的生命周期结束时,其析构函数会被自动调用,这会释放它所持有的任何系统资源。这意味着,如果在函数中创建了一个局部 std::mutex 对象,或者当它的作用域结束时,析构函数会被调用。

2.3 互斥量加锁和解锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号
std::mutex mu;
mu.lock(); // 请求锁定mu.unlock(); // 完成后解锁

调用pthread_ lock 时,可能会遇到以下情况:

  • 互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功
  • 发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互斥量, 那么pthread_ lock调用会陷入阻塞(执行流被挂起),等待互斥量解锁。

2.4 改进后售票代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
int ticket = 100;
pthread_mutex_t mutex;
void *route(void *arg)
{char *id = (char *)arg;while (1){pthread_mutex_lock(&mutex);if (ticket > 0){usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;pthread_mutex_unlock(&mutex);// sched_yield(); 放弃CPU}else{pthread_mutex_unlock(&mutex);break;}}
}
int main(void)
{pthread_t t1, t2, t3, t4;pthread_mutex_init(&mutex, NULL);pthread_create(&t1, NULL, route, (void *)"thread 1");pthread_create(&t2, NULL, route, (void *)"thread 2");pthread_create(&t3, NULL, route, (void *)"thread 3");pthread_create(&t4, NULL, route, (void *)"thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL);pthread_mutex_destroy(&mutex);
}


 

三.死锁

3.1.什么是死锁?

死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态

3.2.死锁四个必要条件

  • 互斥条件:一个资源每次只能被一个执行流使用
  • 请求与保持条件:一个执行流因请求资源而阻塞时,对已获得的资源保持不放
  • 不剥夺条件:一个执行流已获得的资源,在末使用完之前,不能强行剥夺
  • 循环等待条件:若干执行流之间形成一种头尾相接的循环等待资源的关系

3.3 避免死锁

  • 破坏死锁的四个必要条件
  • 加锁顺序一致
  • 避免锁未释放的场景
  • 资源一次性分配

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吴恩达2022机器学习专项课程(一) 6.1 动机第三周课后实验:Lab1使用逻辑回归进行分类

问题预览/关键词 什么是逻辑回归&#xff1f;什么是二分类问题&#xff1f;二分类问题案例如何表达二分类的结果&#xff1f;逻辑回归通常用哪种表达形式&#xff1f;什么是正样本和负样本&#xff1f;什么是阈值&#xff1f;可视化线性回归解决二分类线性回归面对二分类产生的…

Android 跨进程通信

Android中常用的跨进程通信方法有以下几种&#xff1a; Intent、Binder、AIDL、Messenger、ContentProvider。 Intent 可以通过Intent传递数据和消息&#xff0c;但是只能传递一些简单的数据类型&#xff0c;比如字符串、整数等。 示例&#xff1a; 从一个应用程序发送一个字…

jmeter之跨线程关联

1&#xff09;_setproperty函数&#xff1a;将值保存成jmeter属性 2&#xff09;_property函数&#xff1a;在其他线程组中使用property函数读取属性 一、跨线程接口引用变量 1. 法一&#xff1a;jmeter自带函数_setProperty和_property 1. 1线程组 01 创建登录的【HTTP请求】…

1、k8s问题pod从service中剔除

一、起因 redis原来由两服务器的集群变为三服务器的集群&#xff0c;通过statefulset扩展了两节点&#xff0c;并把redis-app-0和redis-app-3从集群中去除&#xff0c;但是由于service路由后端不变&#xff0c;导致程序连接后端仍然可能到redis-app-0和redis-app-3 二、处理 …

常用的跨平台笔记软件OneNote, GTD

keywords: OneNote, GTD 快捷键 C --> Ctrl S --> Shift M --> Alt Cmd --> Command 调整文本格式 功能WindowsMac OS X高亮选中文本C-S-h 或 C-M-h插入超链接C-kCmd-k复制选中文本的格式&#xff08;格式刷&#xff09;C-S-cCmd-M-c应用格式刷到选中文本C-…

分类算法——决策树(五)

认识决策树 决策树思想的来源非常朴素&#xff0c;程序设计中的条件分支结构就是if-else结构&#xff0c;最早的决策树就是利用这类结构分割数据的一种分类学习方法。 决策树分类原理详解 为了更好理解决策树具体怎么分类的&#xff0c;通过一个问题例子&#xff1a; 问题…

C++入门----内联函数auto范围fornullptr指针

1.内联函数 顾名思义&#xff0c;内联函数也是函数的一种&#xff0c;我们在C语言的学习过程里面知道了函数和宏之间的区别和各自的优缺点&#xff1b; 函数的使用需要建立栈帧&#xff0c;宏的使用需要考虑各种符号的优先级问题&#xff0c;很容易出错&#xff0c;因为宏在使…

HarmonyOS开发案例:【闹钟】

介绍 使用后台代理提醒&#xff0c;实现一个简易闹钟。要求完成以下功能&#xff1a; 展示指针表盘或数字时间。添加、修改和删除闹钟。展示闹钟列表&#xff0c;并可打开和关闭单个闹钟。闹钟到设定的时间后弹出提醒。将闹钟的定时数据保存到轻量级数据库。 相关概念 [Canva…

MySQL创建表时添加约束

创建表时添加约束 ①列级约束 演示&#xff1a; CREATE TABLE students( id INT PRIMARY KEY,#主建约束&#xff08;唯一性&#xff0c;非空&#xff09; s_name VARCHAR(10) NOT NULL, #非空 s_sex CHAR(1) CHECK(s_sex男 OR s_sex女),#检查约束(Mysql无效) s_seat INT UNI…

数学建模完整版

模型与适用题型 微分方程传染病预测模型 神经网络 层次分析法 粒子群算法 matlab 优劣解距离法

如何为Postgres数据库设置安全的访问控制和权限管理

文章目录 解决方案1. 使用角色和权限管理2. 配置认证方法3. 使用网络访问控制4. 定期审查和更新权限 示例代码1. 创建角色并分配权限2. 配置密码认证3. 配置网络访问控制 总结 PostgreSQL是一个功能强大的开源关系型数据库系统&#xff0c;提供了丰富的权限和访问控制机制&…

前端表单滑块验证码开发

Jsp页面用javascript加 滑动验证条_jsp验证码滑动实现-CSDN博客 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&quo…

云原生技术助力某制造业巨头构建面向未来的统一技术中台

制造帝国的数字化绮梦 在全球经济一体化和信息化快速发展的今天&#xff0c;制造业的数字化转型已经成为推动产业高质量发展的关键趋势。中国政府高度重视制造业的数字化转型&#xff0c;将其视为实现制造强国战略的核心内容&#xff0c;并出台了一系列政策支持推动发展进程。…

LLM大语言模型(十二):关于ChatGLM3-6B不兼容Langchain 的Function Call

背景 基于本地的ChatGLM3-6B直接开发LangChain Function Call应用&#xff0c;发现其输出的action和action_input非常不稳定。 表现为生成的JSON格式回答非常容易出现不规范的情况&#xff0c;导致LangChain的Agent执行报错&#xff0c;或者进入死循环。 ChatGLM3-6B不兼容La…

基于北京迅为iTOP-RK3588大语言模型部署测试

人工智能&#xff08;AI&#xff09;领域中的大模型&#xff08;Large Model&#xff09;逐渐成为研究的热点。大模型&#xff0c;顾名思义&#xff0c;是指拥有海量参数和高度复杂结构的深度学习模型。它的出现&#xff0c;不仅推动了AI技术的突破&#xff0c;更为各行各业带来…

简单仓库管理系统(增删改查功能)

前端 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>Document</title> …

职场受挫,没有晋升机会怎么办?

和其他人比较没有意义。 每个人的基础不一样&#xff0c;经历不一样&#xff0c;学习方法不一样&#xff0c;无谓的比较只会徒增烦恼。 我们能做的就是&#xff0c;深入了解自己&#xff0c;做自己&#xff0c;找到适合自己的方法&#xff0c;从而快速提升自己。做自己&#…

Pow(x,n)——力扣

python&#xff08;快速幂&#xff09; 50. Pow(x, n) 已解答 中等 相关标签 相关企业 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xn &#xff09;。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;10…

若依ruoyi-vue部署在域名的子目录下应该如何配置

本文相关视频教程&#xff1a;https://www.bilibili.com/video/BV1Fi4y1q74p?p46&vd_source2894aa0e46c09ba98269f266128b6c6e 有些特殊情况需要部署到子路径下&#xff0c;例如&#xff1a;https://www.ruoyi.vip/admin&#xff0c;以下是若依ruoyi-vue部署在域名的子目…

【C++】——类和对象(构造函数,析构函数,拷贝构造函数,赋值运算符重载)

创作不易&#xff0c;多多支持&#xff01; 前言 相信你对这几个知识点有点混淆&#xff0c;相信看完以后&#xff0c;你会对此有一个清晰的认识。 一 类的6个默认成员函数 如果我们写一个类&#xff0c;但是类里面什么都没有&#xff0c;我们称之为空类。 其实这个类也不…