从信号量开始的里牛渴死生活

news2024/9/28 17:47:50

讲讲信号量

POSIX信号量

这个曾经在进程间通信提过一嘴但是没怎么细说,POSIX信号量和SystemV信号量都可用于同步达到无冲突的访问共享资源的目的,POSIX还可以用于线程间同步

初始化
#include <semaphore.h> 
int sem_init(sem_t *sem, int pshared, unsigned int value); 

参数: pshared:0表示线程间共享,非零表示进程间共享

value:信号量初始值  

销毁
int sem_destroy(sem_t *sem);
等待
int sem_wait(sem_t *sem); //P() 

这是等待信号量,会将信号量的值-1 

发布
int sem_post(sem_t *sem);//V() 

这是发布信号量,资源使用完毕,可以归还了,信号量值+1 

环形队列

环形队列也是队列,也要遵守先进先出,哎哟但是我好像就这个没学啊我去

今天晚些时候学吧

逻辑是环状的,但是物理上是线性的,是通过取模运算模拟出来的

当环形队列为空或者为满的时候,head == end

我们需要一个计数器或者牺牲一个空位置区分空和满

我们如今的问题是多线程如何在环形队列中进行生产和消费

那么多线程如何在环形队列中生产和消费?

队列为空的时候让谁先访问呢?

肯定是让生产者先生产啊

队列为满的时候让谁访问?

肯定是让消费者来消费啊

在局部内访问资源有顺序性

大部分情况下这东西

不怎么出现

这样生产和消费会同时进行

我们的结论:

我们不能让生产者把消费者套一个圈

用信号量就能做到勒

消费者关心的资源是什么捏?

数据资源

生产者关心的什么资源?

空间

二者关心的东西不一样,相加为N

 我们可以定义这两个东西,一个是sem_t data_sem=0(开始的时候)

第二个我们叫空间信号量,是sem_t space_sem=N

要有生产者和消费者

写接口,这是RunQueue.hpp:

#pragma once

#include<iostream>
#include<vector>
#include<string>
#include<semaphore.h>

template<typename T>
class RingQueue
{
private:
    void P(sem_t &s)
    {
        sem_wait(&s);
    }
    void V(sem_t &s)
    {
        sem_post(&s);
    }
public:
    RingQueue(int max_cap)
    :_max_cpp(max_cap),_ringqueue(max_cap),_c_step(0),_p_step(0)
    {
        sem_init(&_data_sem,0,0);
        sem_init(&_space_sem,0,max_cap);
    }
    void Push(const T &in)      //生产者
    {
        P(_space_sem);
        _ringqueue[_p_step]=in;
        _p_step++;
        _p_step%=_max_cpp;  //因为是环形队列
        V(_data_sem);    //完成生产要释放资源
    }
    void Pop(T* out)            //消费者
    {
        P(_data_sem);
        *out = _ringqueue[_c_step];
        _c_step++;
        _c_step%=_max_cpp;
        V(_space_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);
    }
private:
    std::vector<T> _ringqueue;
    int _max_cpp;

    int _c_step;
    int _p_step;

    sem_t _data_sem;    //消费者关心
    sem_t _space_sem;   //生产者关心
};

用了一些手段 

这是Main.cc:

#pragma once

#include"RunQueue.hpp"
#include<iostream>
#include<unistd.h>
#include<string>
#include<pthread.h>

void *Consumer(void* args)
{
    RingQueue<int> *rq = static_cast<RingQueue<int>*>(args);
    while (true)
    {
        sleep(1);
        int data = 0;
        //消费
        rq->Pop(&data);
        //处理数据
        std::cout << "Consumer -> " << data << std::endl;
    }
}

void* Productor(void* args)
{
    RingQueue<int> *rq = static_cast<RingQueue<int>*>(args);
    while (true)
    {
        sleep(1);
        //构造数据
        int data = rand() % 10 + 1;
        //生产
        rq->Push(data);
        std::cout << "Productor -> " << data << std::endl;
    }
}

int main()
{
    srand(time(nullptr)^getgid());
    RingQueue<int> *rq = new RingQueue<int>(5);

    pthread_t c,p;
    pthread_create(&c,nullptr,Consumer,rq);
    pthread_create(&p,nullptr,Productor,rq);

    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    return 0;
}

环形队列里也可以存放任务捏

Main.cc:

#pragma once

#include"RunQueue.hpp"
#include"Task.hpp"
#include<iostream>
#include<unistd.h>
#include<string>
#include<pthread.h>

void *Consumer(void* args)
{
    RingQueue<Task> *rq = static_cast<RingQueue<Task>*>(args);
    while (true)
    {
        sleep(1);
        Task t;
        //消费
        rq->Pop(&t);
        //处理数据
        t();
        std::cout << "Consumer -> " << t.result() << std::endl;
    }
}

void* Productor(void* args)
{
    RingQueue<Task> *rq = static_cast<RingQueue<Task>*>(args);
    while (true)
    {
        sleep(1);
        //构造数据
        int x = rand() % 10 + 1;
        int y = rand()%10 + 1;
        Task t(x,y);
        //生产
        rq->Push(t);
        std::cout << "Productor -> " << t.debug() << std::endl;
    }
}

int main()
{
    srand(time(nullptr)^getgid());
    RingQueue<Task> *rq = new RingQueue<Task>(5);

    pthread_t c,p;
    pthread_create(&c,nullptr,Consumer,rq);
    pthread_create(&p,nullptr,Productor,rq);

    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
    return 0;
}

Task.hpp:

#pragma once

#include <iostream>
#include <string>

class Task 
{
public:
    Task() : x(0), y(0) 
    {}
    Task(int a, int b) : x(a), y(b) 
    {}

    // 执行任务,计算结果
    void operator()() 
    {
        result_value = x + y; // 示例操作:计算 x 和 y 的和
    }

    // 返回结果
    int result() const 
    {
        return result_value;
    }

    // 调试输出
    std::string debug() const 
    {
        return "Task: x = " + std::to_string(x) + ", y = " + std::to_string(y);
    }

private:
    int x; // 第一个参数
    int y; // 第二个参数
    int result_value; // 计算结果
};

 这是单生产单消费的情况,那么多生产多消费的情况应该怎么改呢?

有个问题,要不要加锁?

我们要维护生产者和消费者之间的互斥关系,所以需要加锁,多个生产者进来了生产者的下标位置只有一个,于是他们的下标位置就变成了临界资源,那么问题来了,要加几把锁?

要加两把锁

有个问题,加锁这件事情到底是在申请信号量之前还是之后捏?

答案已经很明晰了,,,

肯定是在之后捏

你这么想,信号量相当于电影票,肯定是人手先一张票之后再排队比较好啊,

这样效率比较高捏

#pragma once

#include<iostream>
#include<vector>
#include<string>
#include<pthread.h>
#include<semaphore.h>

template<typename T>
class RingQueue
{
private:
    void P(sem_t &s)
    {
        sem_wait(&s);
    }
    void V(sem_t &s)
    {
        sem_post(&s);
    }
public:
    RingQueue(int max_cap)
    :_max_cpp(max_cap),_ringqueue(max_cap),_c_step(0),_p_step(0)
    {
        sem_init(&_data_sem,0,0);
        sem_init(&_space_sem,0,max_cap);

        pthread_mutex_init(&_c_mutex,nullptr);
        pthread_mutex_init(&_p_mutex,nullptr);
    }
    void Push(const T &in)      //生产者
    {
        P(_space_sem);
        pthread_mutex_lock(&_p_mutex);          //加锁
        _ringqueue[_p_step]=in;
        _p_step++;
        _p_step%=_max_cpp;      //因为是环形队列
        V(_data_sem);           //完成生产要释放资源
        pthread_mutex_unlock(&_p_mutex);    //解锁
    }
    void Pop(T* out)            //消费者
    {
        P(_data_sem);
        pthread_mutex_lock(&_c_mutex);          //加锁
        *out = _ringqueue[_c_step];
        _c_step++;
        _c_step%=_max_cpp;
        V(_space_sem);
        pthread_mutex_unlock(&_c_mutex);        //解锁
    }
    ~RingQueue()
    {
        sem_destroy(&_data_sem);
        sem_destroy(&_space_sem);

        pthread_mutex_destroy(&_c_mutex);
        pthread_mutex_destroy(&_p_mutex);
    }
private:
    std::vector<T> _ringqueue;
    int _max_cpp;

    int _c_step;
    int _p_step;

    sem_t _data_sem;        //消费者关心
    sem_t _space_sem;       //生产者关心

    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};

听着荷叶饭,我要开始升华了 

信号量对资源进行使用为什么不判断一下条件是否满足呢?

因为信号量本身就是判断条件

信号量:是一个计数器,是资源的预定机制,在外部可以不判断资源是否满足,就可以知道内部资源的情况

这种就是二元信号量,二元信号量等同于互斥锁

 多线程让我们能在处理数据和构造数据的过程中并发性高(这俩耗时比较长捏)

加几把锁啊好难啊我不想写了,,,

为什么我要当一个程序猿,我现在确实天天尖叫

世界真是魔幻啊

我们为实验室新建了个GitHub,感觉好像又好起来了,拿一枚蛋黄派作为加入我们的新手礼包

听学长说完实验室的来历之后又莫名自豪

不知道为什么

然后晚上去打羽毛球结果风太大了打不了羽毛球

于是就去小操场和大家一起玩三国杀了

期间我经历了模电作业提交风波

最后还是没写直接把荷叶饭的概率论作业交上去了

还挺燃的

然后不想回宿舍就在小操场躺下了 

然后我们超过了回宿舍时限(虽然可能是故意的只是想给自己一个必须出去的理由)

然后就开始润去KTV了没错又是无用知识点(晚上订KTV要提前预定,否则你会十二点之后过去发现人家满包了)但是我们还是比较幸运的,在辗转了三个KTV之后终于找到了最后一个包间,我们无痛小包升大包,于是开始在实验室拉人(12:50)

但是没有人鸟我们都睡着了

哈哈,我的车又被推上去了

昨天起床下楼还碰到了和我一样没梳头的荷叶饭,,,真是令人忍俊不禁啊 

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

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

相关文章

C++ 9.27

作业&#xff1a; 将之前实现的顺序表、栈、队列都更改成模板类 Stack #include <iostream> using namespace std; template <typename T> class Stack { private: T* arr; // 存储栈元素的数组 int top; // 栈顶索引 int capacity; // 栈的…

工程师 - Windows下使用WSL来访问本地的Linux文件系统

Access Linux filesystems in Windows and WSL 2 从 Windows Insiders 预览版构建 20211 开始&#xff0c;WSL 2 将提供一项新功能&#xff1a;wsl --mount。这一新参数允许在 WSL 2 中连接并挂载物理磁盘&#xff0c;从而使您能够访问 Windows 本身不支持的文件系统&#xff0…

【中医智慧解糖忧】血糖高?中医调理有妙招,自然平衡血糖不是梦!

在快节奏的现代生活中&#xff0c;高血糖已成为困扰许多人的健康难题。面对这一挑战&#xff0c;许多人第一时间想到的是西医的药物治疗&#xff0c;却往往忽略了中医这一博大精深的宝库。事实上&#xff0c;中医以其独特的理论体系和丰富的实践经验&#xff0c;在调理血糖方面…

千亿数据-异地容灾-查询打印——MySQL大数据优化

1. 数据备份策略 - 定期全量备份&#xff1a;制定周期性的全量数据备份计划&#xff0c;确保数据的完整性。 - 增量备份&#xff1a;在全量备份之间进行增量备份&#xff0c;减少备份时间和存储空间。 2. 数据存储 - 分布式存储&#xff1a;利用分布式存储系统来存…

极致cms使用多语言插件,如何修改默认主站语言为英文

jizhicms使用多语言插件&#xff0c;如何修改默认主站语言为英文 第一步&#xff1a;首先安装多语言插件 第二步配置多语言 第三步&#xff1a;极致cms默认的语言版本是中文的&#xff0c;需要修成英文要分三个步骤 1、修改前台&#xff0c;当url中不带语言的时候&#xff0c…

systemd使用入门

systemd负责管理整个操作系统&#xff0c;功能非常强大。我们在实际工作中&#xff0c;常常使用systemd来管理我们的服务。 &#xff08;1&#xff09;想要开机之后自动启动&#xff0c;从而不需要每次开机之后都手动启动进程&#xff0c;可以通过systemd来实现。 &#xff0…

酒水速送小程序开发制作方案

在餐饮娱乐领域&#xff0c;即时酒水配送服务逐渐成为市场新宠。开发一款集在线选购、快速配送、于一体的酒水配送小程序&#xff0c;以满足用户在家中、聚会场所或商业活动中即时获取各类酒水的需求&#xff0c;提升用户体验&#xff0c;拓宽酒水销售渠道。 目标用户 年轻消费…

JavaScript基础第一天

一、JavaScript简介 JavaScript&#xff08;简称“JS”&#xff09; 是一种具有函数优先的轻量级&#xff0c;解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名的&#xff0c;但是它也被用到了很多非浏览器环境中&#xff0c;JavaScript 基于原型编程、…

如何使用Kimi编写商品管理设计文档:包含流程图和用例图

如何使用Kimi编写商品管理设计文档&#xff1a;包含流程图和用例图 在软件开发项目中&#xff0c;商品管理系统是一个常见的需求。它涉及到商品的添加、编辑、删除、查询以及库存管理等功能。编写商品管理设计文档是确保项目顺利进行的关键步骤。以下是如何使用Kimi编写商品管…

青动CRM-E售后V2.0.4

CRM售后管理系统&#xff0c;旨在助力企业销售售后全流程精细化、数字化管理&#xff0c;主要功能&#xff1a;客户、合同、工单、任务、报价、产品、库存、出纳、收费&#xff0c;适用于&#xff1a;服装鞋帽、化妆品、机械机电、家具装潢、建材行业、快销品、母婴用品、办公用…

Vue 自定义组件实现 v-model 的几种方式

前言 在 Vue 中&#xff0c;v-model 是一个常用的指令&#xff0c;用于实现表单元素和组件之间的双向绑定。当我们使用原生的表单元素时&#xff0c;直接使用 v-model 是很方便的&#xff0c;但是对于自定义组件来说&#xff0c;要实现类似的双向绑定功能就需要一些额外的处理…

【JavaScript】搭建一个具有记忆的简洁个人待办网页

1. HTML 结构 文档类型声明&#xff1a;<!DOCTYPE html>这告诉浏览器这是一个 HTML5 文档。HTML 标签&#xff1a;<html lang"zh-CN">表示整个页面的内容&#xff0c;lang"zh-CN" 表示内容使用简体中文。头部信息&#xff1a;<head><…

RabbitMQ 队列之战:Classic 和 Quorum 的性能洞察

RabbitMQ 是一个功能强大且广泛使用的消息代理&#xff0c;它通过处理消息的传输、存储和交付来促进分布式应用程序之间的通信。作为消息代理&#xff0c;RabbitMQ 充当生产者&#xff08;发送消息的应用程序&#xff09;和使用者&#xff08;接收消息的应用程序&#xff09;之…

速查!2024 CSP-J/S第一轮认证成绩查询及晋级分数线

CSP-J/S 2024第一轮认证成绩已于9月27日13:30开放查询&#xff0c;认证者可登录NOI报名系统&#xff0c;在对应活动内查询个人成绩&#xff0c;CSP-J/S 2024第一轮J组得分为89分及以上的选手、S组得分为56分及以上的选手&#xff0c;可以直接晋级第二轮。 Scratch实验室根据NOI…

大模型微调方法(非常详细),收藏这一篇就够了!

引言 众所周知&#xff0c;大语言模型(LLM)正在飞速发展&#xff0c;各行业都有了自己的大模型。其中&#xff0c;大模型微调技术在此过程中起到了非常关键的作用&#xff0c;它提升了模型的生成效率和适应性&#xff0c;使其能够在多样化的应用场景中发挥更大的价值。 那么&…

数据特征工程:如何计算块熵?| 基于SQL实现

目录 0 信息量定义 1 块熵定义 2 问题描述 ​3 数据准备 4 问题分析 5 小结 0 信息量定义 信息量是指从N 个相等可能事件中选出一个事件所需要的信息度量或含量,也就是在辩识N 个事件中特定的一个事件的过程中所需要提问是或否的最少次数。 在一个系统中,等可能事件的数…

【技术文章】PostgreSQL分区表

引言 PostgreSQL作为一款高度可扩展的企业级关系型数据库管理系统&#xff0c;其内置的分区表功能在处理大规模数据场景中扮演着重要角色。本文将深入探讨PostgreSQL分区表的实现逻辑、详细实验过程&#xff0c;并辅以分区表相关的视图查询、分区表维护及优化案例&#xff0c;…

OpenStack Yoga版安装笔记(十四)启动一个实例

1、官方文档 OpenStack Installation Guidehttps://docs.openstack.org/install-guide/ 本次安装是在Ubuntu 22.04上进行&#xff0c;基本按照OpenStack Installation Guide顺序执行&#xff0c;主要内容包括&#xff1a; 环境安装 &#xff08;已完成&#xff09;OpenStack…

树脂法提纯牛胆汁

牛胆汁中除了含有胆酸外&#xff0c;还含有胆红素、胆固醇、卵磷脂、钠、钾、钙、镁、铁、锌等多种成分。这些成分对人体健康具有一定的益处&#xff0c;如胆红素具有抗氧化作用&#xff0c;卵磷脂有助于降低胆固醇&#xff0c;钠、钾、钙等矿物质对于维持人体正常生理功能也是…

Excel 绝对值怎么求?ABS 函数用法详解

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4ca; ABS函数在Excel中用于计算数值的绝对值&#xff0c;这在处理财务、科学和日常办公等领域的数据时非常有用。今天&#xff0c;我们将通过一些具体的日常工作案例&#xff0c;来展示ABS函数的实际应用。 ABS函…