9.【Linux】(死锁问题||线程同步||条件变量||生产者消费者模型)

常见锁的概念

死锁

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

小林coding的例子

死锁必要条件

必须同时满足四个条件才会产生死锁

1.互斥条件:一个资源每次只能被一个执行流使用
2.请求与保持条件(持有并等待条件):一个执行流因请求资源而阻塞时,对已获得的资源保持不放。
3.不可剥夺条件:一个执行流已获得的资源,在未使用完之前,不能强行剥夺。
4.环路等待条件:若干执行流之间形成一种头尾详解的循环等待条件。

解决死锁问题(资源有序分配)

破坏4个必要条件之一即可,最常见的并且可行的就是使用资源有序分配法,来破环环路等待条件。
那什么是资源有序分配法呢?
线程 A 和 线程 B 获取资源的顺序要一样,当线程 A 是先尝试获取资源 A,然后尝试获取资源 B 的时候,线程 B 同样也是先尝试获取资源 A,然后尝试获取资源 B。也就是说,线程 A 和 线程 B 总是以相同的顺序申请自己想要的资源。

其他方法

死锁检测算法、银行家算法。

线程同步

同步问题是保证数据安全的情况下,让线程访问资源具有一定的顺序性从而避免饥饿问题。如果没有适当的同步机制,就可能出现数据不一致、数据竞态条件(race condition)或其他不可预测的行为。

条件变量

允许线程等待某个条件成立(通常与互斥锁一起使用)。当条件不满足时,线程会阻塞并等待其他线程发出信号。它是在多线程程序中用来实现“等待–>唤醒”逻辑常用的方法。它用于维护一个条件,这个条件与条件变量是不同的概念。线程可以使用条件变量来等待某个条件为真,注意这里并不是等待条件变量为真。它允许线程在等待某个条件成立时进入休眠状态,从而避免了不必要的CPU资源浪费,提高了程序的效率和响应速度.

相关函数

初始化

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:互斥量,后面详细解释

????为何要带锁
在让线程在条件变量时等待时,会自动释放传入的锁。当被唤醒该函数返回时会重新持有锁。

如何判断临界资源是否就绪?通过访问临界资源,也必须加锁。等待过程所以必须在加锁和解锁之间。

唤醒等待

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

signal唤醒等待在该条件变量的一个线程,broadcast唤醒等待在该条件变量下的所有线程。

生产者消费者模型

生产者消费者模型(Producer-Consumer Model)是一种常用的并发编程模型,主要用于解决生产数据(或任务)和消费数据(或任务)之间的平衡问题。
生产者(Producer):主要负责生成数据(或任务),并将其放入一个共享的数据缓冲区(如队列、栈等)。当缓冲区满时,生产者通常会等待,直到缓冲区中有空间可以存放新的数据。
消费者(Consumer):主要负责从共享的数据缓冲区中取出数据(或任务)并进行处理。当缓冲区为空时,消费者通常会等待,直到缓冲区中有新的数据可供消费。

基于阻塞队列的CP模型

block.hpp

   #pragma once 

#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
#include<mutex>

template<class T>
class Blockq{
    static const int default_num=20;
public:
    Blockq(int maxcap=default_num)
    :maxcap_(maxcap)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&p_cond_,nullptr);
        pthread_cond_init(&c_cond_,nullptr);
        low_water_=maxcap_/3;
        high_water_=(maxcap_*2)/3;
    }

    T pop()
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size()==0)//防止伪唤醒,用while判断
        {
            pthread_cond_wait(&c_cond_,&mutex_);
        }
        T out=q_.front();
        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(q_.size()==maxcap_){
            pthread_cond_wait(&p_cond_,&mutex_);
        }
        q_.push(in);
        if(q_.size()>high_water_)
            pthread_cond_signal(&c_cond_);
        pthread_mutex_unlock(&mutex_);
    }


    ~Blockq()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);
    }

private:
    std::queue<T> q_;
    int maxcap_;
    pthread_mutex_t mutex_;
    pthread_cond_t p_cond_;
    pthread_cond_t c_cond_;
    int low_water_;
    int high_water_;
};


main.cc

#include"BlockQueue.hpp"
#include"Task.hpp"
#include<ctime>
#include<unordered_map>

std::string ops="+-*/%";
void * Consumer(void* args)
{
    Blockq<Task>* bq=static_cast<Blockq<Task>*>(args);
    while(true)
    {
        //消费
        Task t=bq->pop();
        std::cout<<pthread_self()<<" :"<<"消费一个任务:";
        t.run();
    }
}

void * Productor(void* args)
{
    Blockq<Task>* bq=static_cast<Blockq<Task>*>(args);
    while(true)
    {
        int data1=rand()%10+1;
        int data2=rand()%10+1;
        char op=ops[rand()%5];
        Task t(data1,data2,op);
        usleep(10);
        bq->push(t);
        std::cout<<"生产了一个任务:"<<std::endl;
    }
}

int main()
{
    srand(time(nullptr));
    Blockq<Task>* bq=new Blockq<Task>();
    pthread_t c[3],p[5];
    for(int i=0;i<3;i++)
    {
        pthread_create(c+i,nullptr,Consumer,bq);
    }

    for(int i=0;i<5;i++)
    {
        pthread_create(p+i,nullptr,Productor,bq);
    }

    for(int i=0;i<3;i++)
    {
        pthread_join(c[i],nullptr);
    }

    for(int i=0;i<5;i++)
    {
        pthread_join(p[i],nullptr);
    }
    delete bq;

    return 0;
}

task.hpp

#pragma once 
#include<iostream>

class Task{
private:
    int _a;
    int _b;
    char _op;
    int _result;
public:
    Task(int a,int b,char op)
    :_a(a)
    ,_b(b)
    ,_op(op)
    ,_result(0){}

    void run()
    {
        switch (_op)
        {
        case '+':
            _result=_a+_b;
            break;
        case '-':
            _result=_a-_b;
            break;
        case '*':
            _result=_a*_b;
            break;
        case '/':
            _result=_a/_b;
            break;
        case '%':
            _result=_a%_b;
            break;
        
        default:
            break;
        }
        std::cout<<_a<<_op<<_b<<"="<<_result<<std::endl;
    }
};

makefile

blockqueue:main.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -rf blockqueue

基于信号量和环形队列的CP模型

见上篇博客

读者写者模型

读者写者模型是操作系统中的一种同步与互斥机制,主要用于处理对共享资源的并发访问问题。在这个模型中,存在两种角色:读者和写者,他们共享一个读写场所。
读者是对共享资源进行读取操作的一方,多个读者可以同时并发地读取资源,这是因为读操作并不改变资源的内容,因此读者之间是共享关系。而写者则是进行写操作的一方,写操作会修改共享资源的内容,因此具有排他性,即同一时刻只能有一个写者进行写操作,写者之间是互斥关系

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

等级保护测评试题上

一、单选题 1、下列不属于网络安全测试范畴的是&#xff08;C&#xff09; A&#xff0e;结构安全 B.便捷完整性检查 C.剩余信息保护 D.网络设备防护 2、下列关于安全审计的内容说法中错误的是&#xff08;D&#xff09; A&#xff0e;应对网络系统中的网络设备运行情况、网…

陪玩线下找搭子交友小程序开源版开发

陪玩线下找搭子交友小程序开源版开发 模式是一种线上预约、线下体验的多元化社交平台。 范围广泛&#xff0c;包括电竞陪练、户外运动陪伴、音乐艺术交流、旅游伴游、生活技能指导等&#xff0c;覆盖电竞、运动、音乐、游戏、旅游、文化、艺术、学习等多个领域。 无论是亲子互…

最新游戏陪玩语音聊天系统3.0商业升级独立版本源码+搭建教程

首发价值29800元的最新商业版游戏陪玩语音聊天系统3.0商业升级独立版本源码。 下 载 地 址 &#xff1a; runruncode.com/php/19748.html 1. 新增人气店员轮播功能。 2. UI界面优化&#xff0c;包括游戏图标展示和分类展示的改进。 3. 增加动态礼物打赏功能。 4. 新增礼…

分布式与一致性协议之CAP和Paxos算法(一)

CAP 理论 如何使用BASE理论 以InfluxDB系统中DATA节点的集群实现为例。DATA节点的核心功能是读和写&#xff0c;所以基本可用是指读和写的基本可用。我们可以通过分片和多副本实现读和写的基本可用。也就是说&#xff0c;将同一业务的数据先分片&#xff0c;再以多份副本的形…

录屏功能怎么打开?这3个小技巧你得学会

当我们在使用电子设备时&#xff0c;您是否也想将屏幕上的精彩内容分享给他人&#xff0c;又或者想要记录自己的操作步骤。这时&#xff0c;录屏功能就显得尤为重要。那么&#xff0c;录屏功能怎么打开&#xff1f; 接下来&#xff0c;我将为大家详细介绍3种常见的打开录屏功能…

vue知识

一、初始vue Vue核心 Vue简介 初识 (yuque.com) 1.想让Vue工作&#xff0c;就必须创建一个Vue实例&#xff0c;且要传入一个配置对象 2.root容器里的代码依然符合html规范&#xff0c;只不过混入了一些特殊的Vue语法 3.root容器里的代码被称为【Vue模板】 4.Vue实例和容器…

关于远程桌面与3389端口的深度解析

当我们谈论远程桌面和3389端口时&#xff0c;我们实际上是在探讨Windows操作系统的一个核心功能&#xff0c;该功能允许用户通过网络从任何地点远程控制和管理计算机。而3389端口&#xff0c;正是这一功能所依赖的通信端口。 一、远程桌面的工作原理 远程桌面协议&#xff08;R…

gateway全局token过滤器

添加gateway依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>创建一个tokenFilter 实现全局过滤器GlobalFilter,并且实现fitler方法 Value("${…

qt5-入门-2D绘图-基础

参考&#xff1a; QPainter_w3cschool https://www.w3cschool.cn/learnroadqt/k7zd1j4l.html C GUI Programming with Qt 4, Second Edition 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt 5.12 代码已经测试通过。其他例子日后更新。 目录 基础知识penb…

场外期权交易合法吗?参与场外期权交易需要符合哪些规定?

场外期权交易是合法的金融交易方式&#xff0c;且得到了相应监管部门的支持和规范。它是一种新型的期权交易方式&#xff0c;具有灵活性高、可以满足特定投资者需求的特点。 文章来源/&#xff1a;股指研究院 场外期权是私下协商的&#xff0c;交易双方可根据个人预期、风险承…

《QT实用小工具·四十八》趣味开关

1、概述 源码放在文章末尾 该项目实现了各种样式的趣味开关&#xff1a; 1、爱心形状的switch开关&#xff0c;支持手势拖动、按压效果 2、线条样式的3种开关 项目demo演示如下所示&#xff1a; 使用方式&#xff1a; 1、sapid_switch文件夹加入工程&#xff0c;.pro文件中…

二、VLAN原理和配置

vlan不是协议&#xff0c;是一个技术&#xff0c;虚拟局域网技术&#xff0c;基于802.1q协议。 vlan&#xff08;虚拟局域网&#xff09;&#xff0c;将一个物理的局域网在逻辑上划分成多个广播域的技术。 目录 1.冲突域和广播域 概念 范围 2.以太网帧格式 3.以太网帧封装…

【小程序逆向专栏】某润选房小程序逆向分析

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;不提供完整代码&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未…

【YesPMP】平台最新外包项目,设计、小程序、网站等你来接!

YesPMP平台目前最新项目&#xff0c;有感兴趣的用户&#xff0c;可查看项目参与竞标&#xff0c;免费接单&#xff0c;竞标后由项目方直接与服务商联系&#xff0c;双方直接对接。 1.查看项目&#xff1a;网站网页或pc软件 2.查看项目&#xff1a;数据 …

天冕科技亮相第十七届深圳国际金融博览会!

第十七届深圳国际金融博览会在深圳会展中心正式开幕&#xff0c;天冕科技跟随南山区组团集体亮相&#xff0c;充分展现金融活力。此次金博会&#xff0c;南山区政府共遴选了包括天冕科技在内的三家优秀金融科技企业组团参展&#xff0c;以特色与创新的案例展示了辖区金融业发展…

Ansible-Tower安装破解

主机IP地址版本Ansible192.168.169.2042.9.1Tower192.168.169.2043.6.2 基础环境 systemctl disable firewalld --now && setenforce 0 sed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config mv /etc/yum.repos.d/CentOS-* /tmp/ curl -o /etc/yum.repo…

AI时代来临,电子行业暗藏新机遇!新人如何逆袭,成为行业翘楚?

随着人工智能技术的飞速发展&#xff0c;程序员的工作正迎来前所未有的变革。去年9月&#xff0c;《大西洋月刊》上的一篇文章&#xff0c;由Kelli Mara Korducki所著&#xff0c;直言不讳地指出&#xff1a;“在人工智能时代&#xff0c;计算机科学已不再是那个稳妥的专业选择…

速成python

一个只会c的苦手来总结一下py的语法。没有其他语法基础的不建议看 1. 输入输出 print自带换行&#xff0c;可以写print("Hi", end"")取消换行 a input(你好:) # 默认是str print(type(a)) # 输出a的类型 a int(input()) # 或者a int(a) print(type(…

Vue.js 3 应用开发与核心源码解析 阅读笔记

https://www.dedao.cn/ebook/reader?idV5R16yPmaYOMqGRAv82jkX4KDe175w7xRQ0rbx6pNgznl9VZPLJQyEBodb89mqoO 2022年出的书&#xff0c;针对Vue的版本是3.2.28&#xff0c;当前的版本是 3.4.21。 本书的一大特色是对Vue 3.x的核心源码&#xff08;响应式原理、双向绑定实现、虚…

毅四捕Go设计模式笔记——命令模式

命令模式&#xff08;Command Pattern&#xff09; 为了解决什么问题&#xff1f; 命令模式的目的是将请求发起者和请求执行者解耦&#xff0c;使得请求的发起者不需要知道具体的执行者是谁&#xff0c;也不需要知道执行的具体过程&#xff0c;只需要发送请求即可。 通过使用…
最新文章