linux多线(进)程编程——(9)信号量(二)
前言
上一篇文章我们讲解了信号量的基础用法,这一篇文章我们承接上面的内容,给大家进一步提升对信号量的理解。如果没有看过上一篇文章,请大家移步linux多线(进)程编程——(9)信号量(一)
案例:高性能科研设备开发
(1)小明得到了一个由A公司生产的科研设备,该设备会采集大量医学影像的原始数据并且输出,厂家提供了设备中数据采集软件的原始代码。
(2)小明之前做过一个独立的软件,只要获得原始数据就可以处理数据并且输出重建后的医学图像。
(3)由于设备移植,需要更换A公司生产的设备,因此需要提供一个软件用于实时处理A设备的数据并给用户呈现出重建后的医学图像。项目周期特别短,需要一个尽快可行的方案,减少开发周期,及时拿出产品。
(4)后续可能需要更换多家公司的设备。
案例1的需求分析
(1)需要研发一个科研设备的软件,需要实时性,因此优先考虑设备性能。
(2)项目开发周期短,需要尽可能利用已经有的资源(厂家提供的原始代码,已经有的独立软件)。
(3)尽可能减少耦合性,以防后续再次更换设备。(所以我们不能在厂家提供的原始代码上开发,否则没有可移植性)
技术方案
结合上面的需求,小明的方案是,独立运行厂家提供的数据采集程序与小明个人开发的数据处理与图像重建程序。考虑需要传输大量数据,需求高效性,使用共享内存实现两个程序间的数据传输(不了解共享内存的同学请移步:linux多线(进)程编程——(6)共享内存)。仅需要在两个程序间提供数据传输接口即可,代码开发量大大降低,且防止修改代码结构可能造成的一系列问题。为了防止进程间冲突,还需要一个信号量来完成进程间同步。
使用信号量管理共享内存访问的的流程:同一时刻只能有一个进程访问共享内存。当信号量为值0时,证明共享内存被占用,值为1时证明当前没有进程操作共享内存。
数据发送端开发
接下来我们直接上代码展示,首先是厂家提供的源代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>#define PACKET_SIZE (512 * 512 * sizeof(double) + 1)// 检查设备上电状态,返回0表示正常
int device_check(void);// 外部实现的函数,将数据存储到*_buf指向的空间中,空间动态分配
// 返回值:传输数据的字节数
int recv_data(char** _buf);int getData(void) {int ret = 0;ret = device_check(); // 硬件设备检查if(ret != 0) return ret;/* another fun *//* over */char* buf = NULL;while(1) {ret = recv_data(&buf); // 从硬件外设中获取数据if(ret < 0) return ret;/* another process *//* over */free(buf); // 释放空间buf = NULL;}return 0;
}int main() {int ret = getData(); // 数据获取函数启动if(ret <= 0) { // 消息错误打印// 。。。}return 0;
}
为了能向其他进程传输数据,在这里我们需要提供一个初始化接口initTrans
,用于初始化信号量与共享内存:
/*
功能:数据传输初始化
参数:
dataSize_: [in] 共享内存大小
shmbuf_: [out] 指向共享内存的映射地址
shmid_: [out] 共享内存ID
semid_: [out] 信号量ID
*/
int initTrans(int dataSize_, char** shmbuf_, int* shmid_, int* semid_) {*shmid_ = shmget(1, dataSize_, 0666|IPC_CREAT);if(*shmid_ == -1) printf("initTrans: shared memory init fail\n");else printf("initTrans: shared memory init success\n");*shmbuf_ = (char*)shmat(*shmid_, NULL, 0);if(*shmbuf_ == NULL) printf("initTrans: shared memory map fail\n");else printf("initTrans: shared memory map success\n");*semid_ = semget(1, 1, 0666|IPC_CREAT);if(*semid_ == -1) printf("initTrans: semaphore init fail\n");else printf("initTrans: semaphore init success\n");union sempun {int val; // 用于SETVALstruct semid_ds *buf; // 用于IPC_STAT/IPC_SETunsigned short *array; // 用于GETALL/SETALL} arg;arg.val = 1;if(-1 == semctl(*semid_, 0, SETVAL, arg) ) printf("initTrans: sem init val set fail\n");printf("initTrans: sem init val is : %d\n", semctl(*semid_, 0, GETVAL));printf("initTrans: Trans init success!\n");return 0;
}
还需要一个数据发送接口dataTrans
,向共享内存写入数据。
/*
功能:数据传输
参数:
shmbuf_: [in] 共享内存的映射地址
srcbuf_: [in] 存放要传输数据的缓冲区
dataSize_: [in] 要传输的数据大小
semid_: [in] 信号量ID
*/
int dataTrans(char* shmbuf_, char* srcbuf_, int dataSize_ ,int semid_) {printf("dataTrans: data is sending\n");struct sembuf stbu = {0};stbu.sem_op = -1;stbu.sem_num = 0;stbu.sem_flg = 0;semop(semid_, &stbu, 1);memcpy(shmbuf_, srcbuf_, dataSize_);stbu.sem_op = 1;semop(semid_, &stbu, 1);printf("dataTrans: data send over\n");return 0;
}
最后提供一个资源回收的接口deinitTrans
:
/*
功能:资源回收
参数:
shmbuf_: [in] 共享内存的映射地址
shmid_: [in] 共享内存ID
semid_: [in] 信号量ID
*/
void deinitTrans(char* shmbuf_, int shmid_, int semid_) {if(-1 == shmdt(shmbuf_)) printf("deinitTrans: share memory detach fail\n");else printf("deinitTrans: share memory detach success\n");if(-1 == shmctl(shmid_, IPC_RMID, NULL))printf("deinitTrans: share memory delete fail\n");else printf("deinitTrans: share memory delete success\n");if( -1 == semctl(semid_, 0, IPC_RMID))printf("deinitTrans: sem delete fail\n");else printf("deinitTrans: sem delete success\n");
}
将我们的接口接入程序后,数据发送端变为:
int getData(void) {int ret = 0;ret = device_check();if(ret != 0) return ret;/* another fun */int shmid = -1, semid = -1;char* shmbuf = NULL;initTrans(PACKET_SIZE, &shmbuf, &shmid, &semid);/* over */char* buf = NULL;while(1) {ret = recv_data(&buf);if(ret < 0) return ret;/* another process */dataTrans(shmbuf, buf, ret, semid);sleep(1);/* over */free(buf);buf = NULL;}deinitTrans(shmbuf, shmid, semid);return 0;
}
数据接收端开发
小明开发的程序框架为:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sem.h>#define PACKET_SIZE (512 * 512 * sizeof(double) + 1)// 用于处理数据,滤波,重建等
void dataProcess(char* _iniData, char* proData);
// 开启图窗显示图像
void imageDisplay(char* _iamgeData);void app() {char* databuf = malloc(PACKET_SIZE);char* imagebuf = malloc(PACKET_SIZE);while(1) {dataProcess(databuf, imagebuf);imageDisplay(imagebuf);}
}int main() {app();return 0;
}
与发送端相同,我们需要一个初始化接口initTransRcv
,但在这里我们不需要设置信号量的初始值:
/*
功能:数据传输初始化
参数:
dataSize_: [in] 共享内存大小
shmbuf_: [out] 指向共享内存的映射地址
shmid_: [out] 共享内存ID
semid_: [out] 信号量ID
*/
int initTransRcv(int dataSize_, char** shmbuf_, int* shmid_, int* semid_) {printf("initTransRcv: wait send port init\n"); // 等待发送端初始化sleep(3);*shmid_ = shmget(1, dataSize_, 0666|IPC_CREAT);if(*shmid_ == -1) printf("initTransRcv: shared memory init fail\n");else printf("initTransRcv: shared memory init success\n");*shmbuf_ = (char*)shmat(*shmid_, NULL, 0);if(*shmbuf_ == NULL) printf("initTransRcv: shared memory map fail\n");else printf("initTransRcv: shared memory map success\n");*semid_ = semget(1, 1, 0666|IPC_CREAT);if(*semid_ == -1) printf("initTransRcv: semaphore init fail\n");else printf("initTransRcv: semaphore init success\n");printf("initTransRcv: Trans init success!\n");return 0;
}
还需要一个数据接收接口dataTransRcv
,读取共享内存的数据。此外为了防止数据处理速度大于发送速度,导致内存反复刷新,要增加一个数据判断,判断是否是新数据,这里在发送数据时应该在数据包中放入数据帧号。
/*
功能:数据传输
参数:
shmbuf_: [in] 共享内存的映射地址
srcbuf_: [in] 存放接收到的数据的缓冲区
dataSize_ : [in] 要传输的数据大小
semid_: [in] 信号量ID
*/
int dataTransRcv(char* shmbuf_, char* srcbuf_, int dataSize_ ,int semid_) {struct sembuf stbu = {0};stbu.sem_op = -1;stbu.sem_num = 0;stbu.sem_flg = 0;semop(semid_, &stbu, 1);static int lastID = 0;if(shmbuf_[0] > lastID) { // 判断是否接收新到数据,防止反复刷新内存printf("dataTransRcv: data is receiving\n");memcpy(srcbuf_, shmbuf_, dataSize_);lastID = shmbuf_[0];printf("dataTransRcv: receive new data(indx = %d)\n", lastID);}else printf("buf is not flush\n");stbu.sem_op = 1;semop(semid_, &stbu, 1);return 0;
}
最后提供一个资源回收的接口deinitTransRcv
,这里仅需要分离共享内存的映射即可:
/*
功能:资源回收
参数:
shmbuf_: [in] 共享内存的映射地址
*/
void deinitTransRcv(char* shmbuf_) {if(-1 == shmdt(shmbuf_)) printf("deinitTransRcv: share memory detach fail\n");else printf("deinitTransRcv: share memory detach success\n");
}
将我们的接口接入程序后,数据接收端变为:
void app() {char* databuf = malloc(PACKET_SIZE);char* imagebuf = malloc(PACKET_SIZE);/* interface */int shmid = -1, semid = -1;char* shmbuf = NULL;initTransRcv(PACKET_SIZE, &shmbuf, &shmid, &semid);/* over */while(1) {dataTransRcv(shmbuf, databuf, PACKET_SIZE, semid);dataProcess(databuf, imagebuf);imageDisplay(imagebuf);usleep(200*1000);}deinitTransRcv(shmbuf);
}
完整代码
信号量教学项目-仪器开发
该资源为一个软件框架,主要帮助理解信号量,此外可以在改框架上进行开发。
该资源内部提供了完备的日志输出,用于快速定位问题。
目录说明:
dataGet.c:A公司提供的设备源代码
myapp.c:小明开发的程序
get:由dataGet.c编译出的可执行文件
out:由myapp.c编译出的可执行文件
小结
这节课我们使用了一个案例去帮助大家理解信号量的使用以及如何使用信号量中实现共享内存的访问管理。
主要涉及了:
(1)共享内存操作
(2)信号量操作
通过信号量保证同一时间只有一个进程在操作共享内存。
下一节我们将学习:linux多线(进)程编程——(10)信号
信号与信号量不一样哦!
结束语
(暂时编不出来了哈哈,后面再补上吧)
相关文章:
linux多线(进)程编程——(9)信号量(二)
前言 上一篇文章我们讲解了信号量的基础用法,这一篇文章我们承接上面的内容,给大家进一步提升对信号量的理解。如果没有看过上一篇文章,请大家移步linux多线(进)程编程——(9)信号量(一) 案例…...
编码器---正交编码器
一、正交编码器定义与核心作用 正交编码器(Orthogonal Encoder),又称增量式编码器,是一种通过输出两路相位差90的脉冲信号(A相、B相)来测量旋转角度、速度和方向的传感器。其核心优势是通过A/B相的脉冲顺序…...
【HDFS入门】HDFS故障排查与案例分析:从日志分析到实战解决
目录 1 HDFS故障排查概述 2 三大常见故障类型解析 2.1 块丢失问题处理流程 2.2 副本不足问题架构 2.3 DataNode无法启动诊断 3 日志分析实战技巧 3.1 NameNode日志分析框架 3.2 DataNode日志分析流程 4.1 实战案例分析 4.2 集群性能突然下降 4.2 数据读写异常处理 …...
爆肝整理!Stable Diffusion的完全使用手册(二)
继续介绍Stable Diffusion的文生图界面功能。 往期文章详见: 爆肝整理!Stable Diffusion的完全使用手册(一) 下面接着对SD的文生图界面的进行详细的介绍。本期介绍文生图界面的截图2,主要包含生成模块下的采用方法、调度类型、迭…...
经典算法 表达式求值
表达式求值 问题描述 给你一个只包含、-、*、/、0、1、2、3、4、5、6、7、8、9的字符串求出该字符串所代表的表达式的值。这里的除法,为了简便,为整数除法,所以答案一定也是一个整数。保证0不作被除数。 示例输入 (16*(141))((13)*(74))*…...
【Java】接口interface学习
参考资料::黑马程序员入门到飞起上 1 概述 在学习完抽象类后,我们了解到抽象类中既可以包含抽象方法,也能有普通方法、构造方法以及成员变量等。而接口则是一种更为彻底的抽象形式。在JDK7及之前的版本中,接口内全部为抽象方法&…...
数据结构实验7.1:二叉树的遍历
文章目录 一,实验目的二,实验描述三,基本要求四,算法分析五,实验操作六,示例代码七,运行效果一,实验目的 深入理解树与二叉树的基本概念,包括节点、度、层次、深度等,清晰区分二叉树与一般树的结构特点,为后续学习和应用打下坚实基础。熟练掌握用递归方法实现二叉树…...
seata db模式,nacos注册中心,spring boot ,spring cloud ,jdk1.8 完成的配置步骤
1. 环境准备 确保以下环境已经安装并正常运行: JDK 1.8MySQL(或其他支持的数据库)Nacos Server(用于注册中心和配置中心)Seata Server 2. 配置 Seata Server (1) 下载并解压 Seata 从 Seata 官方 GitHub 下载最新版…...
C++进阶-多态
文章目录 C进阶--多态概念多态的定义及实现多态的构成条件实现多态的两个重要条件虚函数虚函数的重写及覆盖协变析构函数的重写(面试被问及最好需要举例说明)override和final关键字重载,重写(覆盖),隐藏&am…...
Linux教程-常用命令系列三
文章目录 1. 网络安全常用命令1. su (Switch User)2. chmod (Change Mode)3. chown (Change Owner)4. ps (Process Status)5. who6. top7. free8. kill9. gedit10. find总结 2. 字符串显示命令2.1 基本语法2.2 常用选项2.3 核心功能与示例2.3.1 输出字符串2.3.2 输出变量2.3.3 …...
GIS开发笔记(9)结合osg及osgEarth实现三维球经纬网格绘制及显隐
一、实现效果 二、实现原理 按照5的间隔分别创建经纬线的节点,挂在到组合节点,组合节点挂接到根节点。可以根据需要设置间隔度数和线宽、线的颜色。 三、参考代码 //创建经纬线的节点 osg::Node *GlobeWidget::createGraticuleGeometry(float interv…...
nuxt3前端开发以及nuxt3和nuxt2项目的详细差异点
以下是 Nuxt 3 前端开发的详细指南以及与 Nuxt 2 的核心差异总结,涵盖配置、开发模式、API 变化等关键方面: 一、Nuxt 3 前端开发核心要点 1. 项目初始化 # Nuxt 3 npx nuxi init <project-name> cd <project-name> npm install npm run dev# Nuxt 2 (对比) np…...
Android学习总结之APK打包流程
一、预处理阶段(编译前准备) 1. AIDL 文件处理(进程间通信基础) 流程: 用于实现 Android 系统中不同进程间的通信(IPC)。在项目构建时,AIDL 编译器会将 .aidl 文件编译为 Java 接口…...
java面试篇(常见的集合底层原理)
集合 1、arraylist源码分析 三种构造方法: 扩容的逻辑: 2、ArrayList的底层实现原理是什么? ArrayList listnew ArrayList(10)中的list扩容几次 3、如何实现数组和List之间的转换 4、LinkedList和arraylist的区别 5、hashmap的实现原理 二叉…...
RAG框架精选2
原文链接:https://i68.ltd/notes/posts/20250406-llm-rag2/ 清华Hyper-RAG 使用超图驱动的RAG对抗LLM幻觉论文链接:https://arxiv.org/pdf/2504.08758项目仓库:https://github.com/iMoonLab/Hyper-RAG清华Hyper-RAG:利用超图建模高阶关系,让DeepSeek/Q…...
Redis进阶学习
什么是Redis? Redis是一个key-value结构的非关系型数据库,将数据存储在内存中,结构简单(五种数据结构:string、list、set、zset、hash),数据读写速度快,还可以将数据持久化到硬盘上。…...
【读书笔记·VLSI电路设计方法解密】问题63:为什么可测试性设计对产品的财务成功至关重要
可测试性设计至关重要,因为我们不希望将劣质或故障部件交付给客户。向客户交付过多不良部件意味着财务灾难,更会损害企业声誉并导致商业机会流失。 若设计中未嵌入可测试性设计(DFT),区分良品与不良品的唯一方法就是由应用工程师或客户在实际应用环境中测试芯片。此时芯片…...
Federated Weakly Supervised Video Anomaly Detection with Multimodal Prompt
标题:联邦弱监督视频异常检测的多模态提示方法 原文链接:https://ojs.aaai.org/index.php/AAAI/article/view/35398 源码链接:https://github.com/wbfwonderful/Fed-WSVAD 发表:AAAI-2025 摘要(Abstract) …...
计算机视觉与深度学习 | LSTM原理,公式,代码,应用
LSTM(长短期记忆网络)详解 一、原理 LSTM(Long Short-Term Memory)是RNN的改进版本,通过引入门控机制(输入门、遗忘门、输出门)和细胞状态(Cell State),有效解决传统RNN的梯度消失/爆炸问题,擅长捕捉长距离依赖关系。 核心思想: 细胞状态(C_t):贯穿整个时间步…...
UI界面工程,如何使用控制台
我们通常会使用print函数向控制台输出调试信息。但创建UI界面工程时,默认不会显示控制台。 通过如下方法切换到控制台 项目属性—链接器—系统—子系统—窗口改为控制台...
mysql——基础知识
关键字大小写不敏感 查看表结构中的 desc describe 描述 降序中的 desc descend 1. 数据库的操作 1. 创建数据库 create database 数据库名;为防止创建的数据库重复 CREATE DATABASE IF NOT EXISTS 数据库名;手动设置数据库采用的字符集 character set 字符集名;chars…...
UE虚幻4虚幻5动画蓝图调试,触发FellOutOfWorld事件和打印输出,继续DeepSeek输出
找到了一个pdf,本来想写个翻译的,但还是算了,大概看了下,这类文档很全面,内容很多,但都不是我要的,我想要一个动画蓝图,搜索Montage,或者Anim 只占了一行(几百…...
52单片机LED实验
文章目录 前言点亮一个LEDLED闪烁 LED灯亮灭交替LED流水灯 前言 我所用的板子是普中的STC89C52RC,创建文件的过程中如果你发现keil文件找不到单片机依赖,那怎么办呢 下面从创建新项目讲起 首先打开keil软件,点击project new一个新的projec…...
【C++详解】C++入门(一)命名空间、缺省参数、函数重载
文章目录 一、命名空间命名空间的基本特性命名空间的使用 二、C输入输出用法三、缺省参数(默认参数)定义用法 四、函数重载 一、命名空间 命名空间的基本特性 #include <stdio.h> #include <stdlib.h>int rand 10;int main() {// 编译报错:error C23…...
AWS Linux快速指南:5分钟搭建多用户图形界面
一、概述 本指南将帮助您在AWS上快速部署一个支持多用户、带图形界面和浏览器的Linux环境。我们将使用Ubuntu Server作为基础,配合轻量级的Xfce桌面环境和VNC服务。同时,我们还将提供不同用户规模下的实例规格推荐。 二、实例规格推荐 根据您的用户规模,我们推荐以下EC2实例…...
kotlin,编码、解码
kotlin写程序确实简洁,就是函数式编程对我这种用惯了过程的,换思想有难度。package org.exampleimport java.io.File import java.io.FileNotFoundExceptionval byteToHanzi mapOf(0x00 to "凡", 0x01 to "周", 0x02 to "张&q…...
从零创建 Docker 镜像(基于 OCI 格式)
更现代的 OCI 镜像格式,采用了 OCI Image Format Specification,其中文件引用使用 blobs/sha256/<hash> 的形式,层和配置存储在 blobs/sha256/ 目录下,并且包含 LayerSources 字段。这种格式在较新的 Docker 版本和 OCI 兼容…...
JavaScript 版本号比较
问题描述: 实现 : <script>const compare function(v1,v2){const arr1 v1.split(.)const arr2 v2.split(.)for(let i 0;i<arr1.length||i<arr2.length;i){const a arr1[i]||0const b arr2[i]||0if(a>b){return 1}else if(a<b){…...
MySQL为什么默认使用RR隔离级别?
大家好,我是锋哥。今天分享关于【MySQL为什么默认使用RR隔离级别?】面试题。希望对大家有帮助; MySQL为什么默认使用RR隔离级别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认使用 RR(Repeatable Read)…...
第37讲|AI+农业气象建模:预测极端天气对农业的影响
目录 ✨ 导语:天气不可控,但影响可以预测 📦 一、数据准备:融合农业与气象 ⚡ 二、极端天气如何“定义”? 🔧 三、模型选择与结构设计 🔁 时间序列模型:LSTM 🎯 非时序模型:XGBoost / LightGBM 🧪 四、案例实战:用LSTM预测小麦产量下降风险(受极端天气…...
(done) 吴恩达版提示词工程 1. 引言 (Base LLM 和 Instruction Tuned LLM)
url: https://www.bilibili.com/video/BV1Z14y1Z7LJ/?spm_id_from333.337.search-card.all.click&vd_source7a1a0bc74158c6993c7355c5490fc600 LLM 有两种: 1.基础 LLM,通过文本训练数据预测后面的内容。 这种 LLM 当你给它提问:What is…...
Vue如何实现样式隔离
1. 使用 CSS Modules CSS Modules 允许你在 Vue 组件中定义局部作用域的 CSS,这样可以避免全局样式的冲突 步骤如下: 在你的 Vue 组件中,创建一个 <style> 标签并添加 module 属性。 <template><div :class"$style.c…...
Sentinel源码—6.熔断降级和数据统计的实现二
大纲 1.DegradeSlot实现熔断降级的原理与源码 2.Sentinel数据指标统计的滑动窗口算法 2.Sentinel数据指标统计的滑动窗口算法 (1)滑动窗口介绍 (2)StatisticSlot使用滑动窗口算法进行数据统计 (1)滑动窗口介绍 一.滑动窗口原理 滑动窗口不会指定固定的时间窗口起点与终点…...
B+树删除和测试
B树删除和测试 5.1 高级接口:B 树作为键值存储 在本章中,我们将实现 B 树的高级接口,使其能够作为键值存储(Key-Value Store)使用。这些接口包括插入和删除操作,并处理根节点的维护。 1. 插入接口 1.1 I…...
常用算法解析:从基础排序到图论应用
一、算法基础与设计原则 算法是计算机解决问题的核心工具,其五大基本特性决定了程序的可靠性: 有穷性:算法必须能在有限步骤内终止确定性:每步操作无歧义可行性:可被计算机执行输入输出:具备数据交互能力…...
Java Web项目(一)
框架 java web项目总工分为两部分:客户端(前端)和服务端(后端) 客户端发起请求,服务端接受请求并进行处理 发起请求的方式:from表单、jQuery ajax from表单 造成全局的变化,在发…...
兴达易控DP主站网关数据映射快速配置案例
兴达易控DP主站网关数据映射快速配置案例 在工业自动化的领域,不同通讯协议之间的转换是常见的需求。特别是Profibus DP与Modbus-RTU这两种广泛应用于不同系统和设备的通讯协议,它们之间的数据转换显得尤为重要。本文将详细探讨兴达易控Profibus DP主站…...
Tailwindcss 入门 v4.1
以 react 为例,步骤如下: npm create vitelatest my-app -- --template react 选择 React 和 JavaScript 根据上述命令的输出提示,运行以下命令 cd my-app npm install npm run dev 一个 React App 初始化完成。 安装 Tailwindcss theme …...
通过 WebSocket 接收和播放 WSS 协议视频流
1.创建wss协议视频 1.1必备包 npm install ws ffmpeg-installer/ffmpeg fluent-ffmpeg 说明:安装以下三个包。 1.2代码实现 说明:创建WebSocket服务器,端口为8080 import { WebSocket, WebSocketServer } from ws; // 导入 WebSocket 和 W…...
HTML 如何改变字体颜色?深入解析与实践指南
网页上的字体颜色是网页设计中至关重要的元素之一,它像字体大小一样,对于提升用户体验起着举足轻重的作用。精心选择和运用字体颜色,能够增强页面的可读性、突出重点信息、营造特定的情感氛围,甚至直接影响用户的视觉感受和品牌认…...
tigase源码学习杂记-组件化设计
前言 tigase官方号称高度抽象和组件化。这篇文章就记录一下我研究组件化的相关设计 概述 我的理解tigase高度组件化是所有的关键的功能的类,它都称之为组件,即只要继承于BasicComponent,它都可以成为组件,BasicComponent类实现…...
十二、人工神经网络及其应用
写在前面 这部分内容老师说很重要,不管是实验还是考试占比都非常大 AIGC的全称是“Artificial Intelligence Generated Content”,即人工智能生成内容。这一术语通常用于指代通过人工智能技术自动生成的各种类型的内容,如文本、图像、音频和视频等。随着AI技术的发展,AIG…...
vscode使用技巧
一、符号定位技巧 跳转到定义 F12 或右键「Go to Definition」跳转到符号定义位置CtrlClick 直接点击符号跳转(支持变量/函数/类) 符号大纲视图 CtrlShiftO 打开文件符号大纲,支持模糊搜索符号名输入: 分类显示符号(…...
测试基础笔记第七天
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、cat命令二、ls -al命令三、>重定向符号四、>>追加重定向符号五、less/more命令六、grep命令七、|管道符八、clear命令九、head命令十、tail命令十一、…...
FOC控制中的正弦PWM和空间矢量PWM对比与理解
参考: simple foc:https://docs.simplefoc.com/docs_chinese/foc_theory博客:https://blog.csdn.net/qq_43332314/article/details/126449398 一、无刷电机基础原理 1., 原理图:至少三个绕组线圈(定子&…...
【Oracle专栏】函数中SQL拼接参数 报错处理
Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.背景 最近同事反馈了一个很奇怪的问题,即有一个函数,入参是当前年月,主要作用是通过SQL语句将不合规的数据插入到指定表中,插入数据时带上入参的年月参数。当前问题:单独测试SQL没有问题可以执行成功,…...
无意间发现的宝藏项目:开源世界中的演示项目精选合集
🌟无意间发现的宝藏项目:开源世界中的演示项目精选合集 最近在 GitHub 上随手翻了翻 Spring 官方代码仓库,意外发现一个超有趣的演示项目 —— spring-petclinic。一个轻量但结构完整的 Spring 全家桶演示,让人忍不住一探究竟。 这…...
OpenCSG AutoHub v0.5.0 版本发布
OpenCSG AutoHub v0.5.0 版本发布 作为一款智能化自动化操作的浏览器插件,AutoHub不断致力于为用户提供更加高效、便捷的网页浏览体验。本次 v0.5.0版本 的发布,不仅进一步强化了核心功能,还引入了一些创新特性,旨在帮助用户更智…...
基于Python智能体API的Word自动化排版系统:从零构建全流程模块化工作流与版本控制研究
基于Python智能体API的Word自动化排版系统:从零构建全流程模块化工作流与版本控制实践研究 1. 引言2. 研究背景与意义3. 自动排版工作流的设计原理3.1 文档内容提取与解析3.2 样式参数与格式化规则3.3 智能体API接口调用3.4 自动生成与批量处理3.5 与生成式AI的协同4. 系统架构…...
在 Node.js 中设置响应的 MIME 类型
在 Node.js 中设置响应的 MIME 类型是为了让浏览器正确解析服务器返回的内容,比如 HTML、CSS、图片、JSON 等。我们通常通过设置响应头中的 Content-Type 字段来完成。 ✅ 一、什么是 MIME 类型(Content-Type)? MIME(…...