【Linux】线程互斥和同步

目录

线程互斥

相关概念

互斥量mutex

互斥量的接口

初始化互斥量

销毁互斥量

互斥量加锁/解锁

可重入VS线程安全

概念

可重入与线程安全的联系

可重入与线程安全的区别

死锁

死锁的四个必要条件

避免死锁

避免死锁的算法

线程同步

条件变量

条件变量函数 初始化

销毁

等待条件满足

唤醒等待

CP问题 

代码实现


线程互斥

相关概念

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

互斥量mutex

        为了解决多个线程并发的操作共享变量所带来的问题,本质上就是需要一把锁,Linux中提供的锁被称为互斥量。

互斥量的接口

初始化互斥量

初始化互斥量有两种方法:

方法一:静态分配:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

方法二:动态分配:

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                                        const pthread_mutexattr_t *restrict attr);
        参数:
                mutex:要初始化的互斥量
                attr:NULL

销毁互斥量

销毁互斥量时需要注意:

  • 使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要销毁。
  • 不要销毁一个已经加锁的互斥量。
  • 已经销毁的互斥量,要确保后面不会有线程再尝试加锁。

int pthread_mutex_destroy(pthread_mutex_t *mutex)

互斥量加锁/解锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
……
int pthread_mutex_unlock(pthread_mutex_t *mutex);
//返回值 : 成功返回 0, 失败返回错误号

调用 pthread_mutex_lock 时,会有以下几种情况:

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

可重入VS线程安全

概念

线程安全:多个线程并发同一段代码的时候,不会出现不同的结果。常见对全局变量或者静态变量进行操作,并且没有锁保护的情况下,就会出现该问题。

重入:同一个函数被不同的执行流调用,当前一个流程还没有执行完,就有其他的执行流再次进入,我们称之为重入。一个函数再重入的情况下,运行结果不会出现任何不同或者任何问题,则该函数被称为可重入,否则就是不可重入函数。

可重入与线程安全的联系

  • 函数是可重入的,那就是线程安全的。
  • 线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
  • 如果一个函数中有全局变量,那么这个函数既不是线程安全的也不是可重入的。

可重入与线程安全的区别

  • 可重入函数是线程安全函数的一种
  • 线程安全不一定是可重入的,而可重入函数则一定是线程安全的。
  • 如果将对临界资源的访问加上锁,则这个函数是线程安全的,但如果这个重入函数若锁还未释放则会产生死锁,因此是不可重入的。

加锁的本质:用时间换取安全

加锁的表现:线程对于临界区代码串行执行

加锁原则:尽量的保证临界区代码,越少越好

在纯互斥的环境下,如果锁分配不够合理,容易导致其他线程的饥饿问题!当然不是说只要有互斥,必有饥饿。适合纯互斥的场景,就用互斥。

让所有的线程,获取锁按照一定的顺序,也就是按照一定的顺序获取资源--同步。

死锁

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

        只有一把锁也是会出现死锁的情况,一个线程再持有锁的情况下,再申请锁,就会出现死锁。

死锁的四个必要条件

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

避免死锁

  • 破坏死锁的四个必要条件(请求与保持/不剥夺/循环等待)
  • 加锁顺序一致
  • 避免锁未释放的场景
  • 资源一次性分配

避免死锁的算法

  • 死锁检测算法
  • 银行家算法

线程同步

条件变量

  • 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。
  • 例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

条件变量函数 初始化

int pthread_cond_init(pthread_cond_t *restrict cond,
                                const pthread_condattr_t *restrict attr);
 参数:
           cond:要初始化的条件变量
           attr:NULL(条件变量的属性)

销毁

int pthread_cond_destroy(pthread_cond_t *cond)

等待条件满足

int pthread_cond_wait(pthread_cond_t *restrict cond,
                                pthread_mutex_t *restrict mutex);
参数:
        cond:要在这个条件变量上等待
        mutex:互斥量
pthread_cond_wait让线程等待的时候,会让线程释放持有的锁,也就是在等待之前,线程要先持有锁!!

唤醒等待

int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒在等待队列的全部线程
int pthread_cond_signal(pthread_cond_t *cond);//唤醒等待队列的第一个线程

CP问题 

consumer producter

在编写生产消费模型前,我们先梳理一下两者涉及的概念

三种关系

生产者 VS 生产者   互斥关系

消费者 VS 消费者   互斥关系

生产者 VS 消费者   互斥关系,只有互斥可能会导致消费者饥饿问题,所有还要有同步

两种角色

        生产者和消费者

一个交易场所

        特定结构的内存空间

优点

  • 支持忙闲不均
  • 生产和消费进行解耦

代码实现

blockqueue.hpp

#pragma once#include <iostream>
#include <queue>
#include <pthread.h>
template <class T>
class BlockQueue
{static const int defaultnum = 5;static int data=0;
public:BlockQueue(int maxcap = defaultnum):maxcap_(maxcap){phtread_mutex_init(&mutex_,nullptr);pthread_cond_init(&c_cond_,nullptr);pthread_cond_init(&p_cond_,nullptr);low_water_ = maxcap_/3;high_water_ = (maxcap_*2)/3;}T &pop(){pthread_mutex_lock(&mutex_);if(q.size() == 0){//没有东西了,消费者去排队挂起pthread_cond_wait(&c_cond_,&mutex_);}T out = q.pop();//消费了一个,一定有空间给生产者生产,所以这里唤醒生产者if(q.size()<=low_water_)pthread_cond_signal(&p_cond_);pthread_mutex_unlock(&mutex_);return out;}void push(const T &in){pthread_mutex_lock(&mutex_);if(q.size() == maxcap_){//1.调用的时候自动释放锁//2.生产的到达极值不能继续生产了pthread_cond_wait(&p_cond_,&mutex_);}//1.队列没满 2.被唤醒q.push(in);//生产了一个,可以通知消费者来消费了if(q.size()>=high_water_)pthread_cond_signal(&c_cond_);pthread_mutex_unlock(&mutex_)}~BlockQueue(){pthread_mutex_destroy(&mutex_);pthread_cond_destroy(&c_cond_);pthread_cond_destroy(&p_cond_);}
private:std::queue<T> q_;int maxcap_;        //极值,到多少就不生产了int low_water_;int high_water_;    pthread_mutex_t mutex_;pthread_cond_t c_cond_; //消费者条件变量pthread_cond_t p_cond_; //生产者条件变量};

main.cc

#include "BlockQueue.hpp"void *Consumer(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int>*>(args);while(true){//消费int data = bq->pop();std::cout<<"消费了一个数据:"<< data <<std::endl;}
}
void *Productor(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);while(true){//生产data++;bq->push(data);std::cout<<"生产了一个数据:"<<data<<std::end;}
}
int main()
{BlockQueue<int> *bq = new BlockQueue<int>();pthread_t c,p;pthread_create(&c,nullptr,Consumer,bq);pthread_create(&p,nullptr,Productor,bq);pthread_join(c,nullptr);pthread_join(p,nullptr);delete bq; return 0;
}

makefile

test_blockqueue:main.ccg++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clea:rm -f test_blockqueue

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

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

相关文章

语义分割——为什么单通道8bit灰度图像能显示多种色块???

目录 一、问题二、解答2.1 标签图的实际存储格式2.2 标签图的显示颜色2.3 颜色映射示例 三、应用颜色映射3.1 OpenCV显示标签图3.2 Matplotlib显示标签图 四、总结 一、问题 大家在做语义分割时不知道有没有这样的疑惑&#xff0c;使用打标签工具后&#xff0c;标签图是单通道…

项目收获总结--大数据量存储架构设计方案

项目收获总结--大数据量存储架构设计方案 一、背景二、数据存储层技术选型2.1 MySQL2.2 MongoDB2.3 HBase2.4 HBaseElasticSearch 三、HBaseElasticSearch基本原理3.1 前置考虑3.2 HBaseElasticSearch优点3.3 HBaseElasticSearch缺点 四、HBaseElasticSearch数据一致性架构4.1 …

大语言模型-Transformer-Attention Is All You Need

一、背景信息&#xff1a; Transformer是一种由谷歌在2017年提出的深度学习模型。 主要用于自然语言处理&#xff08;NLP&#xff09;任务&#xff0c;特别是序列到序列&#xff08;Sequence-to-Sequence&#xff09;的学习问题&#xff0c;如机器翻译、文本生成等。Transfor…

【UE5】可反射的射线检测

目录 效果 步骤 一、准备射线 二、生成第一次反射后的射线 三、多次反射 四、通过循环进行多次反射 效果 步骤 一、准备射线 1. 新建一个工程&#xff0c;添加一个俯视角游戏资源包 2. 双击打开俯视角游戏地图 删除大纲中的后期处理体积使得地图可以正常显示 3. 添加一…

SAP批量报工源码

SAP批量报工源码,适用于工序少的情景。 *&---------------------------------------------------------------------* *& Report ZPPR106 *& *&---------------------------------------------------------------------* *& *& *&--------------…

网络编程中的TCP和UDP

什么是TCP协议 TCP( Transmission control protocol )即传输控制协议&#xff0c;是一种面向连接、可靠的数据传输协议&#xff0c;它是为了在不可靠的互联网上提供可靠的端到端字节流而专门设计的一个传输协议。 面向连接 &#xff1a;数据传输之前客户端和服务器端必须建立连…

Aouth2单点登录

信息来源B站 不改bug早点睡&#xff0c;北冥 时序图 -----------------------------总结描述 总体流程 浏览器 - 系统1 - 系统2 - 认证中心(SSO) 访问系统1 浏览器&#xff0c;访问系统1&#xff0c;询问认证中心是否登录 未登录&#xff0c;重定向一个登录页面返回给浏…

(二)原生js案例之数码时钟计时

原生js实现的数字时间上下切换显示时间的效果&#xff0c;有参考相关设计&#xff0c;思路比较难&#xff0c;代码其实很简单 效果 代码实现 必要的样式 <style>* {padding: 0;margin: 0;}.content{/* text-align: center; */display: flex;align-items: center;justif…

光盘防水嘛 ? DVD+R 刻录光盘泡水实验

首发日期 2024-07-20, 以下为原文内容: 同志们好, 欢迎来到 胖喵穷人实验室 ! 这里专注于 低成本, 低难度, 低风险 的 “三低” 小实验. 胖喵穷人实验室 (PM-PLab-E)正式名称: 紫腹巨蚊 (Toxorhynchites gravelyi) 系列穷人 (Poor people) 实验室风险警告: 低风险并不是零风险…

人工智能与语音识别:技术进步与应用前景

引言 人工智能&#xff08;AI&#xff09;作为当今科技进步的核心驱动力&#xff0c;正在各个领域展现其变革力量。其中&#xff0c;语音识别技术作为人工智能的重要应用之一&#xff0c;已经深入到我们的日常生活和工作中。从智能助手如Siri、Google Assistant&#xff0c;到智…

kubernetes k8s Deployment 控制器配置管理 k8s 红蓝部署 金丝雀发布

目录 1、Deployment控制器&#xff1a;概念、原理解读 1.1 Deployment概述 1.2 Deployment工作原理&#xff1a;如何管理rs和Pod&#xff1f; 2、Deployment资源清单文件编写技巧 3、Deployment使用案例&#xff1a;创建一个web站点 4、Deployment管理pod&#xff1a;扩…

科研绘图系列:R语言雨云图(Raincloud plot)

介绍 雨云图(Raincloud plot)是一种数据可视化工具,它结合了多种数据展示方式,旨在提供对数据集的全面了解。雨云图通常包括以下几个部分: 密度图(Density plot):表示数据的分布情况,密度图的曲线可以展示数据在不同数值区间的密度。箱线图(Box plot):显示数据的中…

模型剪枝入门

一、定义 1.定义 2. 案例1 3. 全局剪枝案例 4. 全局剪枝案例 5. 自定义剪枝 6. 特定网络剪枝 7. 多参数模块剪枝 8. torch.nn.utils.prune 解读 二、实现 定义 接口&#xff1a; import torch.nn.utils.prune as prune案例1 import torch.nn as nn import torch.nn.utils.…

全部由1组成的子矩形的数量

题目描述&#xff1a; 给定一个二维数组matrix&#xff0c;其中的值不是0就是1&#xff0c;返回全部由1组成的子矩阵的数量。 way&#xff1a; 假设我们遍历矩形的每一行&#xff0c;以当前遍历到的行作为地基&#xff0c;去看这一行的直方图&#xff08;直方图介绍 ->直方…

10.3.3 QGIS点类型注释(Annotation)的应用与二次开发实现

文章目录 前言注释(Annotation)图层QGis中的注释(Annotation)图层二次开发实现线段类型注释(Annotation)点类型Item 总结 前言 介绍注释(Annotation)图层在QGis中的使用以及二次开发的实现说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 注释(Annotation)…

【Unity实战100例】Unity声音可视化多种显示效果

目录 一、技术背景 二、界面搭建 三、 实现 UIAudioVisualizer 基类 四、实现 AudioSampler 类 五、实现 IAudioSample 接口 六、实现MusicAudioVisualizer 七、实现 MicrophoneAudioManager 类 八、实现 MicrophoneAudioVisualizer 类 九、源码下载 Unity声音可视化四…

代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网:55.右旋转字符串

代码随想录算法训练营 Day 9 代码随想录算法训练营第九天 |LeetCode151.翻转字符串里的单词 卡码网&#xff1a;55.右旋转字符串 目录 代码随想录算法训练营前言LeetCode151.翻转字符串里的单词卡码网&#xff1a;55.右旋转字符串 一、LeetCode151.翻转字符串里的单词1.题目链…

laravel为Model设置全局作用域

如果一个项目中存在这么一个sql条件在任何情况下或大多数情况都会被使用&#xff0c;同时很容易被开发者遗忘&#xff0c;那么就非常适用于今天要提到的这个功能&#xff0c;Eloquent\Model的全局作用域。 首先看一个示例&#xff0c;有个数据表&#xff0c;结构如下&#xff1…

一款国外开发的高质量WordPress下载站模板主题

5play下载站是由国外站长开发的一款WordPress主题&#xff0c;主题简约大方&#xff0c;为v1.8版本&#xff0c; 该主题模板中包含了上千个应用&#xff0c;登录后台以后只需要简单的三个步骤就可以轻松发布apk文章&#xff0c; 我们只需要在WordPress后台中导入该主题就可以…

大模型应用如何点燃?

▎****尽管在中国&#xff0c;关于大模型的商业模式的讨论尚显早期&#xff0c;但智能体&#xff0c;尤其是专业智能体&#xff0c;蕴藏着巨大的潜力。 ChatGPT 还没有颠覆世界。 身处“第三次信息革命”&#xff0c;很多人被浓烈的FOMO&#xff08;Fear of Missing Out&…