【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_);//这里有while循环防止伪唤醒的情况while(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_);//这里有while循环防止伪唤醒的情况while(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.xdnf.cn/news/1488820.html

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

相关文章

Stable Diffusion WebUI本地环境搭建

一、项目代码下载 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 二、环境配置 conda create --n stafu python3.10.6 实际上跟自己创建的环境没有关系&#xff0c;项目启动会自动复制这个环境&#xff0c;之后项目根据这个基础环境构建 也可以在自己…

UE5.4内容示例(1)- 学习笔记

https://www.unrealengine.com/marketplace/zh-CN/product/content-examples 《内容示例》是学习UE5的基础示例&#xff0c;可以用此示例熟悉一遍UE5的功能 模型与材质部分 StaticMeshes FBX_Import_Options Material_Advanced Material_Decals Material_Instances Material_N…

5G智能防爆手持终端在石油化工行业中扮演着什么角色?

5G智能防爆手持终端在石油化工行业中扮演着至关重要的角色&#xff0c;主要体现在以下几个方面&#xff1a; 一、确保安全生产 防爆设计&#xff1a;石油化工行业的工作环境往往存在易燃易爆的危险&#xff0c;5G智能防爆手持终端采用特殊材料和设计&#xff0c;能够在这些极端…

华为交换机SSH配置

华为交换机SSH配置 一、 简介 1、SSH概念 SSH是一种用于通过网络连接到远程计算机并执行命令的协议。它提供了加密的通信会话&#xff0c;使得用户可以在不安全的网络中安全地传输数据。SSH协议最初由芬兰的Tatu Ylnen在1995年创建&#xff0c;旨在解决Telnet和非加密的远程…

C++内存管理和模板/stl初识

前言 c兼容C语言&#xff0c;但它因为有类和对象的概念&#xff0c;C语言原生的那套内存管理函数在特定场景下还是有些捉襟见肘的&#xff0c;为此c在C语言的基础上引入新的内存管理方案&#xff0c;今天我们就来简单的认识一下c的内存管理。除此之外&#xff0c;模板也是c引入…

unity2D游戏开发03状态控制

多态和动画 建立player-idle动画&#xff0c;取玩家最后两个图片 选中playcontroller控制器 将玩家动画拖进去 右键player-idle,选择set as layer Default state 右键点击Any State ,点击Make Transition 结果 动画参数 动画参数是动画控制器定义的变量&#xff0c;点击Param…

【leetcode 详解】生成特殊数字的最少操作【中等】(C++思路精析)

题目见下&#xff1a; 测试数据: 解题思路笔记&#xff1a; 最初拿到这道题是很蒙的&#xff0c;联想不到什么数据结构的模型&#xff08;肯定是笔者积累太少了&#xff09;&#xff0c;甚至惯性地想怎么实现“删除数字”的操作&#xff1a;在原字符串中抽出一个字符然后将剩…

js轮播图制作

实现一个简单的JavaScript轮播图可以通过以下步骤完成&#xff1a; 创建HTML结构&#xff0c;包括轮播图容器和图片列表。 使用CSS进行样式设置&#xff0c;包括隐藏多余的图片。 使用JavaScript编写函数来控制图片的切换。

异常处理和swagger使用

全局异常处理类 定义全局异常处理类&#xff0c;会将错误全部提交到这个异常处理类中进行处理&#xff0c;这个类会将处理的统一结果响应给前端&#xff0c;如果不添加异常处理类&#xff0c;异常不会按照统一的响应格式进行&#xff0c;前端无法识别&#xff0c;当然也可以在…

vue3 常用的知识点

setup:容许在script当中书写组合式API 并且vue3的template不再要求唯一的根元素 <script setup>const name app; </script>组合式API的用法&#xff1a; 可以直接在script标签中定义变量或者函数&#xff0c;然后直接在template当中使用 <template>{{mes…

文件上传总结

一、原理 通过界面上的上传功能上传了一个可执行的脚本文件&#xff0c;而WEB端的系统并未对其进行检测或者检测的逻辑做的不够好&#xff0c;使得恶意用户可以通过文件中上传的一句话木马获得操控权 二、绕过方法 1>前端绕过 1.删除前端校验函数 checkFile() 2.禁用js…

如何实现ECharts图表根据屏幕大小自适应?

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue-ECharts自适应 目录 前言 1920*1080分辨率示图 8184*2432分辨率示图 以vue3ts开发为例 (…

高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图

目录 高效工作流&#xff1a;用Mermaid绘制你的专属流程图 一、流程图的使用场景 1.1、流程图flowChart 1.2、使用场景 二、如何使用mermaid画出优雅的流程图 2.1、流程图添加图名 2.2、定义图类型与方向 2.3、节点形状定义 2.3.1、规定语法 2.3.2、不同节点案例 2.…

昇思25天学习打卡营第1天|简单深度学习

前言 昇思MindSpore是一个全场景深度学习框架&#xff0c;旨在实现易开发、高效执行、全场景统一部署三大目标。 其中&#xff0c;易开发表现为API友好、调试难度低&#xff1b;高效执行包括计算效率、数据预处理效率和分布式训练效率&#xff1b;全场景则指框架同时支持云、边…

SpringBoot添加密码安全配置以及Jwt配置

Maven仓库&#xff08;依赖查找&#xff09; 1、SpringBoot安全访问配置 首先添加依赖 spring-boot-starter-security 然后之后每次启动项目之后&#xff0c;访问任何的请求都会要求输入密码才能请求。&#xff08;如下&#xff09; 在没有配置的情况下&#xff0c;默认用户…

【2024最新版】Stable diffusion汉化版安装教程(附SD安装包),一键激活,永久免费!

目前广泛使用的Stable Diffusion Web UI简称(SDWebUI)是发布在开源平台Github上的一个Python项目,与通常的软件安装方法不同,这个项目并不是下载并安装即可使用的应用程序,而是需要准备执行环境,编译源码. 如果你是一个新手不会安装,现在可以直接使用一键启动包. 例如:国内的…

计算机网络实验-RIP配置与分析

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、相关知识 路由信息协议&#xff08;Routing Information Protocol&#xff0c;RIP&#xff09;是一种基于距离向量&#xff08;Distance-Vector&…

noVNC使用与介绍

noVNC使用与介绍报告 1. 概述 VNC&#xff08;Virtual Network Console&#xff0c;虚拟网络控制台&#xff09;是一种流行的远程桌面访问协议&#xff0c;它允许用户通过网络连接到远程计算机的图形界面。VNC协议的实现通常包括两个主要组件&#xff1a;服务器端&#xff08…

不同行情下算法的具体使用!

上一篇我们说到了不同公司算法交易的区分&#xff0c;有朋友提出了不同的行情下的算法交易应该怎么使用&#xff0c;小编今天就带大家了解下&#xff01;当然具体实际状况百出&#xff0c;这种可以实际为准&#xff08;韭菜修养全拼实际探讨交流&#xff09;&#xff01; 我们在…

Java:实现RSA加密与验证的方法详解

1 RSA简介 RSA加密是一种非对称加密。可以在不直接传递密钥的情况下&#xff0c;完成解密。这能够确保信息的安全性&#xff0c;避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程&#xff0c;分别称为公钥和私钥。两者之间有数学相关&#xff0c;该加…