[Linux]生产消费者模型
目录
一、生产消费者模型概念
1.概念
2.模块构成
3.协作机制
二、基于BlockingQueue的多CP问题
1.BlockQueue模块
2.Task任务模块
3.创建多线程以及整合模块
三、基于信号量的环形队列CP模型
1.POISX信号量接口
初始化信号量
PV操作
信号量销毁
2.模型简述
3.代码实现
一、生产消费者模型概念
1.概念
生产者消费者模型按名字来听就一定有生产者和消费者成员,生产者将自己生产的物品交给消费者,这就是最简单的生产消费协同。但是这样的话,生产者生产之后就一定要当面交给消费者,然后消费者不接收生产者就无法生产,这样就会有弊端了。如果说破生产者生产的快,但是消费者消费速度慢,那么生产者就需要等待消费者将东西买走后,才能继续生产,就会大大降低产能和效率。
所以接下来引入了超市的这一中间概念,生产者可以将生产的东西放到超市里面,不需要直接给消费者,这样的话,生产者的产能就不会受到消费者的影响了,而且消费者也可能随时去超时获取自己想要的东西,而不是说生产者生产出来,消费者就必须接收了。这个就是生产消费者模型的大概框架。
生产消费者模式是一种经典的多线程或多进程并发协作的一种模式。他主要用于解决数据的产生和消费速度不一致的问题,实现了功能解耦、时间解耦以及处理速度的解耦,同时保证了数据的完整性和正确性。功能解耦:生产者专注生产,不关心数据如何被消费者处理;消费者专注处理,不关心数据如何生产的。时间解耦:生产者和消费者(CP)之间不需要同步运行,在满足各自条件下进行工作就可以。处理速度解耦:CP之间不需要互相等待对方,所以处理速度快的一方那么就会一直以高速的方式工作,而慢速的一方则慢慢 执行即可,有中间的共享资源区作为数据的缓冲地带。
2.模块构成
分为生产者、消费者以及缓冲区三部分,生产者和消费者可以是一个线程、进程或者软件模块,生产者将生产的数据放入缓冲区,消费者从缓冲区中取出数据后做相应的处理工作。
3.协作机制
该模型一定涉及到执行流的互斥与同步问题了,生产者与消费者之间存在互斥关系,生产者访问缓冲区的时候,消费者是不可以访问的,消费者访问的时候,同样的生产者也是不可以访问的。因为生产和消费二者访问缓冲区的时候,会对缓冲区的数据做修改,那么就会有线程安全问题,所以要实现互斥机制。当然二者之间也有同步关系,缓冲区中没有数据时,消费者不能进行访问缓冲区,当生产者生产数据之后,会通知消费者访问的。
对于多生产多消费的情况下,也就是生产者和消费者都有很多线程。生产和消费都会修改缓冲区。所以生产者与生产者之间,消费者与消费者之间,也属于多线程访问共享资源,也是要实现互斥的。
上述概括下来,就是生产者之间、消费者之间的互斥以及生产者消费者之间的互斥与同步。
二、基于BlockingQueue的多CP问题
1.BlockQueue模块
该模块定义了一个任务队列,也就是CP问题的缓冲区部分、以及生产线程和消费线程对于该缓冲区的操作方法。当生产者要放入任务的时候,要先判断缓冲区中是否有空间,如果有空间的话,就放入任务,并且通知消费进程取出任务,当没有空间的时候,就进行等待条件变量就绪,这个条件变量的唤醒是由消费进程取出数据后,唤醒的,唤醒生产进程放入数据。
对于消费进程要取出任务的时候,首先判断缓冲区有没有任务,如果有的话,就取出任务,并通知生产进程放入数据,也就是唤醒当时因为缓冲区满了,而阻塞在条件变量中的等待线程。当没有任务的时候,就阻塞在条件变量中等待生产进程唤醒。
生产线程和消费线程之间通过锁实现的互斥操作,通过条件变量实现了同步的顺序操作。
#pragma once#include <iostream>
#include <queue>
#include <pthread.h>// 缓冲区默认容量
static const int default_capacity = 5;//生产消费者模型类
template <class T>
class BlockQueue
{
private:std::queue<T> _task_queue; // 任务队列int _capacity; // 队列容量pthread_mutex_t _mutex; // 锁pthread_cond_t _c_cond; // customer条件变量pthread_cond_t _p_cond; // productor条件变量public:// 构造函数BlockQueue(int capacity = default_capacity):_capacity(capacity){//初始化锁和条件变量pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_c_cond, nullptr);pthread_cond_init(&_p_cond, nullptr);}//生产者--将任务放入任务队列void Push(const T& task){//加锁pthread_mutex_lock(&_mutex);//判断缓冲区是否满了,如果满了的话,就一直通知消费者取出数据//使用while是防止伪唤醒。while(_capacity == _task_queue.size()){//释放锁,并等待消费者通知可以生产pthread_cond_wait(&_p_cond, &_mutex);}//有空间了,放入任务_task_queue.push(task);//通知消费者可以取数据了pthread_cond_signal(&_c_cond);//解锁pthread_mutex_unlock(&_mutex);}//消费者--将任务从任务队列取出void PoP(T* task){//加锁pthread_mutex_lock(&_mutex);//判断是否有数据,没有就进行等待while(_task_queue.empty()){//释放锁,并等待生产者通知可以消费pthread_cond_wait(&_c_cond, &_mutex);}//有数据了,取出数据*task = _task_queue.front();_task_queue.pop();//通知生产者可以生产了pthread_cond_signal(&_p_cond);//解锁pthread_mutex_unlock(&_mutex);}//析构函数~BlockQueue(){//锁和条件变量的销毁pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_c_cond);pthread_cond_destroy(&_p_cond);}
};
2.Task任务模块
定义的是计算两个元素的加减法类
#pragma once#include <iostream>
#include <unistd.h>
#include <string>static const int defaultValue = 0;
static const std::string str = "+-";// 计算加减法的任务类
class Task
{
private:int _x;int _y;char _op;int _result;public://构造与析构函数Task() {}Task(int x, int y, char op): _x(x), _y(y), _op(op), _result(defaultValue) {}~Task() {}void Run(){switch (_op){case '+':_result = _x + _y;break;case '-':_result = _x - _y;break;default:std::cout << "op is error" << std::endl;break;}}// 运行任务重载函数void operator()(){Run();std::cout << _x << _op << _y << "=" << _result << std::endl;sleep(2);}
};
3.创建多线程以及整合模块
该模块则是定义了生产线程和消费线程具体线程函数。以及创建线程、定义任务队列类等操作。
#include <cstdlib>
#include <vector>
#include <string>
#include <cstring>
#include <pthread.h>
#include "BlockQueue.hpp"
#include "Task.hpp"// 线程传递的参数
struct ThreadData
{BlockQueue<Task> *_cp; // 生产者消费者模型对象std::string _thread_name; // 线程名称// 构造函数ThreadData(BlockQueue<Task> *cp, std::string name): _cp(cp), _thread_name(name) {}
};
// 消费者线程函数
void *Costomer(void *arg)
{// 接收参数ThreadData *data = (ThreadData *)arg;while (true){// 获取任务Task task;data->_cp->PoP(&task);std::cout << data->_thread_name << " run task : ";// 执行任务task();}return nullptr;
}
// 生产者线程参数
void *Productor(void *arg)
{// 接收参数ThreadData *data = (ThreadData *)arg;while (true){// 生产任务数据int data1 = rand() % 10;int data2 = rand() % 10;char op = str[rand() % str.size()];Task task(data1, data2, op);// 将任务放入队列data->_cp->Push(task);std::cout << data->_thread_name << " push task into queue : " << data1 << op << data2 << std::endl;}return nullptr;
}int main()
{// 生产随机数种子srand((uint16_t)time(nullptr) ^ getpid() ^ pthread_self());// 创建生产者消费者模型对象BlockQueue<Task> *cp = new BlockQueue<Task>();// 创建生产者消费者线程std::vector<pthread_t> custumer_thread(5);std::vector<pthread_t> productor_thread(5);// 消费者for (int i = 0; i < 5; i++){// 线程idpthread_t tid;// 构造线程参数std::string thread_name = "customer-" + std::to_string(i);ThreadData data(cp, thread_name);// 创建线程pthread_create(&tid, nullptr, Costomer, &data);// 放入数组中custumer_thread.push_back(tid);}// 生产者for (int i = 0; i < 5; i++){// 线程idpthread_t tid;// 构造线程参数std::string thread_name = "productor-" + std::to_string(i);ThreadData data(cp, thread_name);// 创建线程pthread_create(&tid, nullptr, Productor, &data);// 放入数组中productor_thread.push_back(tid);}// 线程等待for (size_t i = 0; i < custumer_thread.size(); ++i){if (pthread_join(custumer_thread[i], nullptr) != 0){std::cerr << "等待消费者线程结束失败" << std::endl;}}for (size_t i = 0; i < productor_thread.size(); ++i){if (pthread_join(productor_thread[i], nullptr) != 0){std::cerr << "等待生产者线程结束失败" << std::endl;}}// 释放资源delete cp;return 0;
}
三、基于信号量的环形队列CP模型
1.POISX信号量接口
其实和System V信号量的作用基本上是一样的,只是接口上有区别。
初始化信号量
int sem_init(sem_t* sem, int pshared, unsigned int value);
第一个参数是传递要初始化的信号量;第二个参数表示信号量是用于进程间(非零值)还是线程间(零值)共享;第三个参数则是信号量的初始值。
PV操作
int sem_wait(sem_t* sem); //申请操作
int sem_post(sem_t* sem); //释放操作
信号量销毁
int sem_destory(sem_T* sem);
2.模型简述
该模型使用了锁实现了线程之间的互斥,信号量的方式实现了同步机制。但是这里的互斥只有生产者和生产者、消费者和消费者之间的互斥,没有生产者与消费者之间的互斥。因为使用了信号量记录了该资源区域的使用情况,用信号量表示了剩余空间的个数和存在的资源的个数,相当于将一个大的资源区域分成了若干个小区域。同时配合指针记录生产者下一次放数据的位置,消费者下一次取数据的位置。所以生产者线程和消费者线程两者访问不到同一个位置,所以也就不存在两个的互斥问题了。
信号量实现的同步是,当space剩余空间信号量为0的时候,生产线程无法放入数据,会等待消费线程取出数据,当消费线程取出数据后,会释放一个space信号量,那么生产线程就可以申请到信号量了,就可以放入数据了。放入数据之后,会将data信号量释放一个,表示着队列中的数据量多了一个。
在申请信号量和锁的顺序上,应该是先申请信号量,信号量代表的是该线程对于想要获取的资源是否存在,如果存在的话,再去为了访问资源而申请锁,如果说没有资源的话,申请到锁也没用,所以说应该先去申请信号量,之后再去申请锁资源。而且先申请锁的话,只会有一个线程到达申请信号量的步骤,而先申请信号量的话,可以有多个线程到达申请锁的位置等待锁资源。
经过上述阐述,因为生产者和消费者没有互斥的关系,所以要给生产者和消费者各设定一把锁去保证线程安全。同时还有设定两个信号量,一个是剩余空间信号量,另一个是剩余资源的信号量。
3.代码实现
#pragma once#include <iostream>
#include <pthread.h>
#include <vector>
#include <semaphore.h>// 环形队列默认大小
static const int default_capacity = 5;template <class T>
class RingQueue
{
private:std::vector<T> _ringQueue; // 环形队列int _capacity; // 最大容量int _p_step; // 生产者放入任务的位置int _c_step; // 消费者取出任务的位置sem_t _space_sem; // 剩余空间信号量sem_t _data_sem; // 剩余任务信号量pthread_mutex_t _p_mutex; // 生产锁pthread_mutex_t _c_mutex; // 消费锁private://申请信号量操作void P(sem_t &sem) { sem_wait(&sem); }//释放信号量操作void V(sem_t &sem) { sem_post(&sem); }public://构造函数RingQueue(int capacity = default_capacity):_ringQueue(capacity), _capacity(capacity), _p_step(0), _c_step(0){//初始化信号量,剩余空间为capacity,剩余任务数据为0sem_init(&_space_sem, 0, _capacity);sem_init(&_data_sem, 0, 0);//初始化锁pthread_mutex_init(&_p_mutex, nullptr);pthread_mutex_init(&_c_mutex, nullptr);}//生产者放入任务操作void Push(const T& task){//申请信号量并加锁P(_space_sem);pthread_mutex_lock(&_p_mutex);//放入任务_ringQueue[_p_step] = task;//更新生产者指针位置_p_step++;_p_step %= _capacity;//解锁并释放信号量pthread_mutex_unlock(&_p_mutex);V(_data_sem);}//消费者取出任务操作void Pop(T* task){//申请信号量并加锁P(_data_sem);pthread_mutex_lock(&_c_mutex);//取出任务*task = _ringQueue[_c_step];//更新消费者指针位置_c_step++;_c_step %= _capacity;//解锁并释放信号量pthread_mutex_unlock(&_c_mutex);V(_space_sem);}//析构函数~RingQueue(){//销毁信号量和锁sem_destroy(&_space_sem);sem_destroy(&_data_sem);pthread_mutex_destroy(&_p_mutex);pthread_mutex_destroy(&_c_mutex);}
};
相关文章:
[Linux]生产消费者模型
目录 一、生产消费者模型概念 1.概念 2.模块构成 3.协作机制 二、基于BlockingQueue的多CP问题 1.BlockQueue模块 2.Task任务模块 3.创建多线程以及整合模块 三、基于信号量的环形队列CP模型 1.POISX信号量接口 初始化信号量 PV操作 信号量销毁 2.模型简述 3.…...
从零用java实现 小红书 springboot vue uniapp (9)消息推送功能
前言 移动端演示 http://8.146.211.120:8081/#/ 前面的文章我们主要完成了个人资料修改 消息页优化 这篇文章我们讲解消息推送 推送页面 因为我们的推送消息都在一个页面 所以我们可以复用消息的websokcet推送 首先需要在 点赞表 收藏表 关注表 回复表 都添加未读字段 MESSAG…...
zookeeper监听机制(Watcher机制)
文章目录 引言I zookeeper监听机制Watcher机制实现分布式的通知功能触发事件种类Watcher的三个过程II watch机制特点一次性触发事件封装event异步发送先注册再触发常见的通知状态和事件类型III 应用案例(Kafka)Kafka的消息模型Kafka在Zookeeper中保存的元数据Kafka 基于Contr…...
企业开通部署 Azure OpenAI 流程:如何创建一个AI聊天机器人
由于众所周知的原因,国内没法直接调用 OpenAI 接口。 下面我将演示企业如何开通 Azure OpenAI 服务,以及如何使用 C# 调用 Azure OpenAI 接口创建一个 Console 应用程序并实现聊天机器人功能。 1开通 Azure OpenAI 服务 要开通 Azure OpenAI 服务&…...
【Linux基础指令】第一期
一、Linux的介绍 Linux是一个开源的操作系统,性能、稳定性、安全性方面上都是很优秀的,所以它一直是企业后端系统的首选。所以其图形化界面并不是Linux的必需品,所以我们避免不了要使用命令行的形式来使用Linux,也就离不开…...
使用 Rust 和 WASM 打造高性能 Web 应用
在现代 Web 开发中,前端性能是衡量用户体验的重要指标之一。随着 WebAssembly (WASM) 的崛起,它为开发者提供了一种在浏览器中运行高性能代码的方式。而 Rust,作为一门以性能和安全性著称的编程语言,与 WASM 的结合使得构建高效的…...
SQL Server中可以通过扩展事件来自动抓取阻塞
在SQL Server中可以通过扩展事件来自动抓取阻塞,以下是详细流程: 开启阻塞跟踪配置: • 执行以下SQL语句来启用相关配置: EXEC sp_configureshow advanced options, 1; RECONFIGURE; EXEC sp_configure blocked process thresh…...
无网络时自动切换备用网络环境
目录 背景目标为什么需要做自动网络切换网络切换手段 网络环境实现思路和代码部署脚本开机自动执行附录连接两个网络时的路由问题 背景 目标 学校实验室有两个网络环境,我电脑使用网线连接稳定但低速的网络A,使用WiFi连接高速但不稳定的网络B。因此&am…...
回顾2024年重磅AI发布汇总
2024年在人工智能领域出现了不少值得关注的发布和进展,以下是根据时间线索,对一些亮点突破进行了总结: 二月 Stability AI 宣布推出Stable Diffusion 3。 Google 升级了 Bard 中的人工智能聊天功能,基于新的Gemini Pro模型&…...
基类指针指向派生类对象,基类指针的首地址永远指向子类从基类继承的基类首地址
文章目录 基类指针指向派生类对象,基类指针的首地址永远指向子类从基类继承的基类起始地址。代码代码2 基类指针指向派生类对象,基类指针的首地址永远指向子类从基类继承的基类起始地址。 代码 #include <iostream> using namespace std;class b…...
Postman接口测试02|接口用例设计
目录 六、接口用例设计 1、接口测试的测试点(测试维度) 1️⃣功能测试 2️⃣性能测试 3️⃣安全测试 2、设计方法与思路 3、单接口测试用例 4、业务场景测试用例 1️⃣分析测试点 2️⃣添加员工 3️⃣查询员工、修改员工 4️⃣删除员工、查询…...
负载均衡服务器要怎么配置?
目录 一、概述: 二、硬件配置: 三、操作系统配置: 四、负载均衡软件: 五、网络配置: 六、软件安装步骤: 6.1 安装 Nginx 6.2 安装 LVS 6.3 安装 HAProxy 6.4 安装 Keepalived 一、概述࿱…...
技术速递|通过 .NET Aspire 使用本地 AI 模型
作者:Aaron Powell 排版:Alan Wang 使用本地 AI 模型是无需将资源部署到云中即可在自己的机器上进行实验的好方法。在本文中,我们将探讨如何使用 .NET Aspire 与 Ollama 来本地运行 AI 模型,同时利用 Microsoft.Extensions.AI 抽象…...
esp32开发笔记之一:esp32开发环境搭建vscode+ubuntu
最近想用esp32做一个物联网项目,踩坑N个终于有点心得,写下来避免和我一样的小白踩无谓的坑。 写在前面: 第一,大家一定要用linux系统作为编译工具,速度上是windows无法比的,不要因为不熟悉linux而选择win…...
vue el-table 数据变化后,高度渲染问题
场景:el-table设置了height属性,但是切换查询条件后再次点击查询重新获取data时,el-table渲染的高度会有问题,滚动区域变矮了。 解决办法:使用doLayout方法,在表格数据渲染后调用doLayout方法可以重新布局…...
unity学习15:预制体prefab
目录 1 创建多个gameobject 2 创建prefab 2.1 创建prefab (类) 2.2 prefab 是一个文件 2.3 prefab可以导出 3 创建prefab variant (子类) 3.1 除了创建多个独立的prefab, 还可以创建 prefab variant 3.2 他…...
Harbor 安装教程
一、安装 Docker 安装必要的一些系统工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加 Docker 软件源信息 sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo修改软件源配置 sudo sed -i sdow…...
HTML5 波动动画(Pulse Animation)详解
HTML5 波动动画(Pulse Animation)详解 波动动画是一种动态效果,使元素周期性地放大和缩小,给人一种脉动的感觉。以下是如何使用 CSS 和 HTML5 创建波动动画的详细说明。 1. 基本概念 波动动画:通过改变元素的大小来…...
【运维】如何检查电脑正常异常和关机日志? 1074正常关机或重启 6006正常关机 41非正常关机 6008异常关机
事件 ID 1074:正常关机或重启,由用户或程序请求触发。 事件 ID 6006:正常关机,表示系统已正确关闭。 事件 ID 41:非正常关机,可能是由于电源问题、硬件故障或系统崩溃导致。 事件 ID 6008:异常关…...
解决后端控制台报错Error updating database
数据库字段 对应实体类字段 private BigDecimal maths; private BigDecimal chinese; private BigDecimal english; 新增数据时后端控制台报错 Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for…...
(2023|NIPS,LLaVA-Med,生物医学 VLM,GPT-4 生成自指导指令跟随数据集,数据对齐,指令调优)
LLaVA-Med: Training a Large Language-and-Vision Assistant for Biomedicine in One Day 目录 LLaVA-Med: Training a Large Language-and-Vision Assistant for Biomedicine in One Day 0. 摘要 1. 简介 2. 相关工作 3. 生物医学视觉指令数据 4. 将多模态对话模型适配…...
I2C学习笔记
前言 我一直不是特别喜欢读文档,习惯了通过视频学习,因为视频能更直观地展现信息,给人一种更生动、形象的感觉。然而,随着学习的内容逐渐增多,我发现并不是所有的知识点都能在视频中找到,或者视频中展示的…...
JetPack——ViewModel
前提阅读 JetPack——Lifecycle Jetpack——LiveData ViewModel是什么? ViewModel 类是一种业务逻辑或屏幕级状态容器。它用于将状态公开给界面,以及封装相关的业务逻辑。 它的主要优点是,它可以缓存状态,并可在配置更改后持久…...
【Java 学习】对象赋值的艺术:Java中clone方法的浅拷贝与深拷贝解析,教你如何在Java中实现完美复制
💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助! 👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持&#x…...
【计算机网络】课程 实验四 配置快速生成树协议(RSTP)
实验四 配置快速生成树协议(RSTP) 一、实验目的 1.理解快速生成树协议RSTP的工作原理。 2.掌握如何在交换机上配置快速生成树。 二、实验分析与设计 【背景描述】 某学校为了开展计算机教学和网络办公,建立了一个计…...
SpringBootWeb案例-1(day10)
准备工作 需求 & 环境搭建 需求说明 环境搭建 步骤: 准备数据库表(dept、emp)创建 springboot 工程,引入对应的起步依赖(web、mybatis、mysql 驱动、lombok)配置文件 application.properties 中引入 mybatis 的配置信息&…...
攻防世界 Web_php_wrong_nginx_config
打开题目地址,显示为登录页面。尝试用御剑扫描一下,发现了admin页面,点进去显示如下 点开控制台,发现如下 isLogin参数为0。尝试抓包并该islogin参数为1,返回依旧不变。 再扫描,发现robots.txtÿ…...
【VUE+ElementUI】通过接口下载blob流文件设置全局Loading加载进度
下载Blob流文件,并以服务形式显示文件下载进度 1、下载接口 增加 config参数,并用...config将该属性加入到请求中; xxapi.js文件中设置downloadFile下载接口 // 下载文件 export function downloadFile(data, config) {return request({ur…...
行为树详解(6)——黑板模式
【动作节点数据共享】 行为树中需要的参数可以来自游戏中的各个模块,如果仅需从多个模块获取少量参数,那么可以直接在代码中调用其他模块的单例继而层层调用获取数据。 如果获取的参数量很大,从架构上看,我们需要通过加一个中间…...
【prometheus】Pushgateway安装和使用
目录 一、Pushgateway概述 1.1 Pushgateway简介 1.2 Pushgateway优点 1.3 pushgateway缺点 二、测试环境 三、安装测试 3.1 pushgateway安装 3.2 prometheus添加pushgateway 3.3 推送指定的数据格式到pushgateway 1.添加单条数据 2.添加复杂数据 3.SDk-prometheus-…...
耗时一天,我用AI开发了AI小程序
小码哥从事前后端开发近十年,但是随着技术的更新迭代,有时候没有时间和精力去优化UI、实现一些前后端功能,以及解决一些bug。特别是我想开发小码哥AI的移动端,但觉得自己没有那么多时间去研究移动端了,准备放弃了&…...
Java 日期时间格式化标准
文章目录 Java日期时间格式化符号ISO 8601中的日期时间ISO 8601标准的定义ISO 8601日期时间格式 周数年份ISO 8601中的周数年份Java中的周数年份 Java跨年日期格式化BUG注意事项 Java日期时间格式化符号 JDK官网截图: 格式化符号梳理: 符号描述符号用…...
undolog,redolog,binlog分别是做什么的?
在数据库系统中(尤其是 MySQL),Undo log、Redo log 和 Binlog 是用于实现数据持久性和一致性的重要日志机制。 1. Undo Log(回滚日志) 功能: 用于事务回滚:记录事务开始前的状态,以…...
NRF24L01模块STM32-接收端
前言 在调试接收端时,建议先看下下篇文章NRF24L01调试心得 环境: 芯片:STM32F103C8T6 Keil:V5.24.2.0 一、接收端初始化 void NRF24l01_rx_mode(void) {NRF24L01_CE(0);NRF24l01_write_buf(NRF_WRITE_REG TX_ADDR, (uint8_t *)TX_ADDRE…...
核磁机器学习 | 机器学习和深度学习算法在fMRI中的应用
摘要 功能磁共振成像(fMRI)是目前应用最广泛的脑图像动态分析技术之一,通常结合多种算法来分析复杂的动态数据。近年来,机器学习和深度学习算法在分析fMRI数据方面的应用呈指数级增长。然而,由于文献中存在大量算法,选择合适的机器…...
【数据结构-堆】力扣3296. 移山所需的最少秒数
给你一个整数 mountainHeight 表示山的高度。 同时给你一个整数数组 workerTimes,表示工人们的工作时间(单位:秒)。 工人们需要 同时 进行工作以 降低 山的高度。对于工人 i : 山的高度降低 x,需要花费 workerTimes…...
web前端-html
HTML部分 HTML:超文本标记语言。是万维网web编程的基础,web是建立在超文本基础上的。HTML 是万维网的基石 打开www.baidu.com的页面源代码可见 超文本标记超的含义 1.最重要的标签,超链接标签,可跳转页面,关联所有页…...
单片机-定时器中断
1、相关知识 振荡周期1/12us; //振荡周期又称 S周期或时钟周期(晶振周期或外加振荡周期)。 状态周期1/6us; 机器周期1us; 指令周期1~4us; ①51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器…...
计算机网络 (31)运输层协议概念
一、概述 从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。运输层的一个核心功能是提供从源端主机到目的端主机的可靠的、与实际使用的网络无关的信息传输。它向高层用…...
【学Rust开发CAD】2 创建第一个工作空间、项目及库
文章目录 一、 创建工作空间二、新建项目(可执行文件)三、 新建库(库文件)四、更新项目依赖五、编写代码七、总结 在 Rust 中,工作空间(workspace)允许你管理多个相关的包(crate&…...
使用GitLab+Jenkins搭建CICD执行环境
使用GitLabJenkins搭建CI\CD执行环境 前言什么是DevOps?什么是CI/CD?使用GitLabJenkins搭建CI\CD执行环境GitLab安装1. 安装和配置所需的依赖2. 下载并安装极狐GitLab3. 登录极狐GitLab 实例4.常用gitlab指令5.修改密码 Jenkins安装1.Jenkins 的主要特点…...
微信小程序——创建滑动颜色条
在微信小程序中,你可以使用 slider 组件来创建一个颜色滑动条。以下是一个简单的示例,展示了如何实现一个颜色滑动条,该滑动条会根据滑动位置改变背景颜色。 步骤一:创建小程序项目 首先,使用微信开发者工具创建一个…...
Mac中配置vscode(第一期:python开发)
1、终端中安装 xcode-select --install #mac的终端中安装该开发工具 xcode-select -p #显示当前 Xcode 命令行工具的安装路径注意:xcode-select --install是在 macOS 上安装命令行开发工具(Command Line Tools)的关键命令。安装的主要组件包括:C/C 编…...
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
业务场景 在目前常见的中后台管理系统中,比较常见的是固定的布局方式包裹页面,但一些特殊页面,比如:登录页面、注册页面、忘记密码页面这些页面是不需要布局包裹的。 但在 Next.js AppRouter 中,必须包含一个根布局文…...
Linux环境下确认并操作 Git 仓库
在软件开发和版本控制中,Git 已成为不可或缺的工具。有时,我们需要确认某个目录是否是一个 Git 仓库,并在该目录中运行脚本。本文将详细介绍如何确认 /usr/local/src/zcxt/backend/policy-system-backend 目录是否是一个 Git 仓库,…...
海陵HLK-TX510人脸识别模块 stm32使用
一.主函数 #include "stm32f10x.h" // Device header #include "delay.h" #include "lcd.h" #include "dht11.h" #include "IOput.h" #include "usart.h" //#include "adc.h" …...
MATLAB语言的正则表达式
MATLAB 中的正则表达式使用指南 引言 在数据处理和文本分析中,正则表达式是一种强大而灵活的工具。MATLAB 作为一种广泛应用于科学计算和数据分析的编程语言,提供了对正则表达式的支持,使得用户可以方便地进行字符串匹配与处理。本文将深入…...
【CVPR 2024】【遥感目标检测】Poly Kernel Inception Network for Remote Sensing Detection
0.论文摘要 摘要 遥感图像(RSIs)中的目标检测经常面临几个日益增加的挑战,包括目标尺度的巨大变化和不同范围的背景。现有方法试图通过大核卷积或扩张卷积来扩展主干的空间感受野来解决这些挑战。然而,前者通常会引入相当大的背…...
笔记-使用ffmpeg产生rtsp视频流,然后用进行VLC播放
笔记-使用ffmpeg产生rtsp视频流,然后用进行VLC播放 1.软件配置1.1下载安装好**ffmpeg**1.2使用EasyDarwin创建RTSP服务器 2.FFmpeg找本地摄像头名字3.FFmpeg推流命令3.1使用VLC实现拉流 1.软件配置 1.1下载安装好ffmpeg ffmpeg官网 本地下载 1.2使用EasyDarwin创…...
Ubuntu20.04中EasyConnect启动报错
安装路径 /usr/share/sangfor/EasyConnect 方法 通过 ./EasyConnect获得错误代码,其中‘Failed to load module "canberra-gtk-module"’可以忽略,主要是‘Harfbuzz version too old (1.3.1)’这个问题,后边的版本号可能因系统不…...