Linux 深入浅出信号量:从线程到进程的同步与互斥实战指南
知识点1【信号量概述】
信号量是广泛用于进程和线程间的同步和互斥。信号量的本质 是一个非负的整数计数器,它被用来控制对公共资源的访问
当信号量值大于0的时候,可以访问,否则将阻塞。
PV原语对信号量的操作,一次P操作使信号量减一,一次V操作使信号量加一。
信号量的类型:sem_t
信号量用于互斥:不管多少个任务互斥,只需要一个信号量,信号量应初始化为1
先P操作,再V操作
大家看上面这张图,若任务A抢到该任务量,信号量被初始化为1,由于先P(减一),导致其他线程(进程)被阻塞,实现互斥的功能,然后执行任务A,V操作(加一),其他任务抢锁,循环上面的过程。
信号量用于同步:有多少个任务,就需要多少个信号量,最先执行的任务对应的信号量为1,其他信号量全部为0
下面介绍一下流程
每个任务先P自己,然后V下一个要执行的任务的信号量
详细介绍:
如图,我们先将sem1初始化1,任务A执行P操作,其他任务被阻塞,执行任务A函数体,任务A结束后,执行要执行任务sem2的V操作,又由于sem1的值为0,即使有循环,也不需要担心A任务继续执行
知识点2【信号量的API】
1、初始化信号量sem_init()
-
函数介绍
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value);
函数功能:
创建一个信号量并初始化它的值。一个无名信号在被使用前必须先初始化
参数:
sen:信号量的地址
pshared:
等于0,信号量在线程间共享
非0:信号量在进程间共享
value:信号量的初始值
返回值:
成功:0
失败:-1
2、信号量减一 P操作 sem_wait()
-
函数介绍
#include <semaphore.h> int sem_wait(sem_t *sem);
函数功能:
将信号量减一。如果信号量为0,则阻塞,大于0则可以减一
参数:
信号量的地址。
返回值:
成功:0
失败:-1
int sem_trywait(sem_t *sem);*
函数功能:
尝试将信号量减一,如果信号量的值为0,不阻塞,立即返回,大于0可以加一
参数:
信号量的地址。
返回值:
成功:0
失败:-1
3、信号量加一 V操作 sem_post()
-
功能介绍
#include <semaphore.h> int sem_post(sem_t *sem);
函数功能:
将信号量加一
参数:
信号量的地址
返回值:
成功:0
失败:-1
4、销毁信号量
-
功能介绍
#include <semaphore.h> int sem_destroy(sem_t *sem);
函数功能:
销毁信号量
参数:
信号量的地址
返回值:
成功:0
失败:-1
知识点3【信号量用于线程的互斥】
代码步骤
1、创建 初始化 阻塞回收线程 3个
2、线程函数创建void *名(void *arg)
封装一个函数my_printf()
这里用的函数实现的功能都是一样的,可以用同一个函数,但是为了提高观看的直观性,我们分成了3个进程函数
在这里我们运行一下,验证函数功能
3、全局创建,初始化,销毁信号量 1个
4、在线程函数中执行PV操作
代码演示
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>//封装my_printf() 函数
void my_printf(char *);
//线程函数声明
void *my_fun01(void *arg);
void *my_fun02(void *arg);
void *my_fun03(void *arg);//全局创建信号量
sem_t sem;int main(int argc, char const *argv[])
{srand(time(NULL));//创建线程 3 个pthread_t tid1,tid2,tid3;//信号量初始化sem_init(&sem,0,1);//初始化信号地址,线程信号量,初始化值1//初始化线程pthread_create(&tid1,NULL,my_fun01,(void *)"pthread A ");pthread_create(&tid2,NULL,my_fun02,(void *)"pthread B ");pthread_create(&tid3,NULL,my_fun03,(void *)"pthread C ");//销毁线程pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//摧毁信号量sem_destroy(&sem);return 0;
}
//my_printf() 函数实现
void my_printf(char *arr)
{while(*arr != 0){printf("%c",*arr);fflush(stdout);usleep(1000 * 100);arr++;}
}
//线程函数实现
void *my_fun01(void *arg)
{while(1){ //p操作sem_wait(&sem);//函数体my_printf((char *)arg);//v操作sem_post(&sem);//关索后休眠,防止重复抢锁//重要!!!!!usleep(1000 * 1000 *(rand()%4 + 1));}return NULL;
}
void *my_fun02(void *arg)
{while(1){ //p操作sem_wait(&sem);//函数体my_printf((char *)arg);//v操作sem_post(&sem);//关索后休眠,防止重复抢锁usleep(1000 * 100 *(rand()%4 + 1));}return NULL;
}
void *my_fun03(void *arg)
{while(1){ //p操作sem_wait(&sem);//函数体my_printf((char *)arg);//v操作sem_post(&sem);//关索后休眠,防止重复抢锁usleep(1000 * 100 *(rand()%4 + 1));}return NULL;
}
代码运行结果
这个是执行完1,2步骤后函数功能验证运行结果:
完整代码的运行结
知识点4【信号量用于线程的同步】
同步操作我们只需要改一下上述代码 但是为了让大家更好地理解 我将扔把全部代码发出
执行顺序:进程A,C,B
这里我先标出不同点地方:
1、信号量的个数
2、信号量的初始化和销毁
3、线程函数中PV原语步骤
整体代码演示:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>//封装my_printf() 函数
void my_printf(char *);
//线程函数声明
void *my_fun01(void *arg);
void *my_fun02(void *arg);
void *my_fun03(void *arg);//全局创建信号量 同步 三个进程创建三个信号量
sem_t sem1,sem2,sem3;int main(int argc, char const *argv[])
{srand(time(NULL));//创建线程 3 个pthread_t tid1,tid2,tid3;//信号量初始化sem_init(&sem1,0,1);//初始化信号地址,线程信号量,初始化值1sem_init(&sem2,0,0);//初始化信号地址,线程信号量,初始化值0sem_init(&sem3,0,0);//初始化信号地址,线程信号量,初始化值0//初始化线程pthread_create(&tid1,NULL,my_fun01,(void *)"pthread A ");pthread_create(&tid2,NULL,my_fun02,(void *)"pthread B ");pthread_create(&tid3,NULL,my_fun03,(void *)"pthread C ");//销毁线程pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//摧毁信号量sem_destroy(&sem1);sem_destroy(&sem2);sem_destroy(&sem3);return 0;
}
//my_printf() 函数实现
void my_printf(char *arr)
{while(*arr != 0){printf("%c",*arr);fflush(stdout);usleep(1000 * 100);arr++;}
}
//线程函数实现
void *my_fun01(void *arg)
{while(1){ //p操作sem_wait(&sem1);//函数体my_printf((char *)arg);//v操作sem_post(&sem3);//关索后休眠,防止重复抢锁//重要!!!!!usleep(1000 * 1000 *(rand()%2 + 1));}return NULL;
}
void *my_fun02(void *arg)
{while(1){ //p操作sem_wait(&sem2);//函数体my_printf((char *)arg);//v操作sem_post(&sem1);//关索后休眠,防止重复抢锁usleep(1000 * 100 *(rand()%4 + 1));}return NULL;
}
void *my_fun03(void *arg)
{while(1){ //p操作sem_wait(&sem3);//函数体my_printf((char *)arg);//v操作sem_post(&sem2);//关索后休眠,防止重复抢锁usleep(1000 * 100 *(rand()%4 + 1));}return NULL;
}
代码运行结果:
知识点5【无名信号量 用于 有血缘关系的进程间互斥】
互斥仍只需要一个信号量
有血缘关系的进程 说明 需要fork 创建子进程
现在只有一个问题 无名信号量是什么?
现在我们想一下 如果子进程1中,我们对一个变量的值进行修改,子进程2 中的值会改变吗?
答案是不会的,那我们该如何实现互斥和同步呢?
这里只需要找到子进程间能够互相识别的部分即可。这里利用我们 之前讲的进程间的共享内存中的磁盘映射mmap。
好了,现在思路有了 我们来写一下代码实现的步骤
代码实现步骤
1、进程的创建 父进程负责管理子进程的空间,子进程负责操作
2、父进程进行信号量磁盘映射,这里我们使用匿名映射
创建子进程,会不会重复映射呢?这个大家放心是不会的,因为系统会识别,父进程映射成功,子进程映射会失败的
3、进程中先实现功能基本输出,并进行验证
4、验证后再完成互斥操作
代码实现
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>#define NUM 2
//打包my_printf函数
void my_printf(char *arr);
int main(int argc, char const *argv[])
{//创建一个数组用来存储 子进程的id 在本项目中不需要 目的是帮助大家回忆pid_t arr[NUM] = {0};//映射mmap信号量sem_t *sem = (sem_t *)mmap(NULL,sizeof(sem_t),PROT_WRITE|PROT_READ,MAP_SHARED | MAP_ANONYMOUS,-1,0);//信号量的初始化sem_init(sem,1,1);//父进程创建两个子进程int i = 0;for (;i < NUM; i++){arr[i] = fork();if(arr[i] == -1){perror("fork");_exit(-1);}else if(arr[i] == 0){break;}}//子进程1 打印worldif(i == 0){//P操作sem_wait(sem);//函数体my_printf("world");//V操作sem_post(sem);_exit(-1);}//子进程2 打印helloelse if(i == 1){//P操作sem_wait(sem);//函数体my_printf("hello");//V操作sem_post(sem);_exit(-1);}//父进程 回收空间waitpidwhile(1){int ret = waitpid(-1,NULL,WNOHANG);if(ret < 0){break;}}//销毁信号量sem_destroy(sem);return 0;
}
void my_printf(char *arr)
{while(*arr != 0){printf("%c",*arr);fflush(stdout);usleep(1000 * 200);//0.2s打印一次arr++;}return;
}
这里我们补充一个小点:
MAP_ANONYMOUS是匿名的意思,如果用了这个在文件描述符必须写-1
代码运行结果
1、没有实现互斥的情况
2、实现互斥的情况
知识点5【无名信号量 用于 有血缘关系的进程间同步】
代码演示
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>#define NUM 2
//打包my_printf函数
void my_printf(char *arr);
int main(int argc, char const *argv[])
{//创建一个数组用来存储 子进程的id 在本项目中不需要 目的是帮助大家回忆pid_t arr[NUM] = {0};//映射mmap信号量 由于有两个子进程,并且要完成同步操作,因此我们需要完成两次映射磁盘sem_t *sem1 = (sem_t *)mmap(NULL,sizeof(sem_t),PROT_WRITE|PROT_READ,MAP_SHARED | MAP_ANONYMOUS,-1,0);sem_t *sem2 = (sem_t *)mmap(NULL,sizeof(sem_t),PROT_WRITE|PROT_READ,MAP_SHARED | MAP_ANONYMOUS,-1,0);//我们这里实现先遍历 world 再遍历 hello//信号量的初始化sem_init(sem1,1,1);sem_init(sem2,1,0);//父进程创建两个子进程int i = 0;for (;i < NUM; i++){arr[i] = fork();if(arr[i] == -1){perror("fork");_exit(-1);}else if(arr[i] == 0){break;}}//子进程1 打印worldif(i == 0){//P操作sem_wait(sem1);//函数体my_printf("world");//V操作sem_post(sem2);_exit(-1);}//子进程2 打印helloelse if(i == 1){//P操作sem_wait(sem2);//函数体my_printf("hello");//V操作sem_post(sem1);_exit(-1);}//父进程 回收空间waitpidwhile(1){int ret = waitpid(-1,NULL,WNOHANG);if(ret < 0){break;}}//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
}
void my_printf(char *arr)
{while(*arr != 0){printf("%c",*arr);fflush(stdout);usleep(1000 * 200);//0.2s打印一次arr++;}return;
}
代码运行结果
下面将标出不同的地方:
代码中遇到的问题:
1、子进程的创建步骤 有些模糊
逻辑,循环中,应是只有子进程才会break,父进程要一直运行循环,不能是因为是break退出。
2、造成了死锁
结束
代码重在练习!
代码重在练习!
代码重在练习!
今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏夹关注,谢谢大家!!!
今天的内容,中有遗漏了信号量用于无血缘关系的进程的互斥与同步
是因为我在写的过程中遇到了一些问题,我解决后将进行补充。
相关文章:
Linux 深入浅出信号量:从线程到进程的同步与互斥实战指南
知识点1【信号量概述】 信号量是广泛用于进程和线程间的同步和互斥。信号量的本质 是一个非负的整数计数器,它被用来控制对公共资源的访问 当信号量值大于0的时候,可以访问,否则将阻塞。 PV原语对信号量的操作,一次P操作使信号…...
github配置ssh,全程CV
1)随便找一个文件夹右键进入git bash 2)验证是否已有公私钥文件 cd ~/.ssh ls如果不存在则生成然后获取 生成时一直回车 ssh-keygen -t rsa -C "xxxxxx.com" cd ~/.ssh cat id_rsa.pub如果存在则直接获取 cd ~/.ssh cat id_rsa.pub3)复制 4…...
MySQL——存储
一、什么是存储过程 存储过程(Stored Procedure) 是预编译并存储在数据库中的一段SQL代码集合,支持参数传递、流程控制和返回值。通过类似“方法调用”的方式执行,存储过程将复杂业务逻辑封装在数据库层,简化应用开发…...
matlab中进行海浪模型仿真
matlab中进行海浪模型仿真,采用优化处理算法,进行防止干扰的海浪算法设计 BarhPlot.m , 180 wave.m , 1649...
边缘计算与隐私计算的融合:构建数据经济的“隐形护盾“
在数据成为核心生产要素的今天,边缘计算与隐私计算的交汇正在重塑技术生态。这并非简单的技术叠加,而是一场关于数据主权、算力分配与信任机制的深度博弈。本文将从"数据流动的拓扑学"视角,探讨二者融合如何重构数字社会的基础设施…...
实现表单验证
给Form.ITem组件绑定 name和rules字段 #增加表单验证的触发事件 失焦 onblur 添加多条验证逻辑 串行验证逻辑 实现表单提交验证 获得的值的属性名由form组件中的name属性决定 如果表单验证通过自动触发属性onFinish绑定的回调函数获得提交内容 封装request模块...
图论-BFS搜索图/树-最短路径问题的解决
续上篇~图论--DFS搜索图/树-CSDN博客 先看第一次学习的博客!!👇👇👇👇 👉 有一些问题是广搜 和 深搜都可以解决的,例如岛屿问题,这里我们记dfs的写法就好啦,…...
大数据学习(107)-sql中case使用场景
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
数据战略新范式:从中台沉淀到服务觉醒,SQL2API 如何重塑数据价值链条?
一、数据中台退烧:从 “战略神话” 到 “现实拷问” 曾几何时,数据中台被视为企业数字化转型的 “万能解药”,承载着统一数据资产、打破业务壁垒的厚望。然而,大量实践暴露出其固有缺陷:某零售企业投入 500 万元建设中…...
MyBatis SqlSessionFactory 批量执行实战
在 MyBatis 中,批量操作是处理高并发数据写入的核心场景之一。通过 SqlSessionFactory 配置批处理执行器(ExecutorType.BATCH),可以显著提升数据库操作的效率。本文将结合 Spring 框架,深入解析如何高效配置和使用 MyB…...
【初阶数据结构】——算法复杂度
一、前言 1、数据结构是什么? 数据结构(Data Structure)是计算机存储、组织数据的⽅式,指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤,所以我们要学各式各样的数据结构, 如&…...
Oracle数据库数据编程SQL<00. 课外关注:rownum、rowid、level、row_number 对比详解与实战>
更多Oracle学习内容请查看:Oracle保姆级超详细系列教程_Tyler先森的博客-CSDN博客 目录 一、基本概念与区别 二、ROWNUM 详解与实战 1. 基本特性 2. 典型应用 2.1 分页查询(Oracle传统方式) 2.2 限制返回行数 2.3 随机抽样 3. 注意事…...
凸优化基础
文章目录 目录**第1讲:凸优化基础****第2讲:凸优化建模****第3讲:对偶理论****第4讲:梯度下降法****第5讲:牛顿法与内点法****第6讲:次梯度与近端方法****第7讲:分布式凸优化****第8讲ÿ…...
LeetCode面试热题150中12-18题学习笔记(用Java语言描述)
Day 03 12、 O ( 1 ) O(1) O(1)时间插入、删除元素和获取元素 需求:实现RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否…...
开源模型集成接口
一、OpenRouter 概述 OpenRouter是一个开源的大模型API路由器,旨在将各种AI模型和服务集成到一个统一的接口中,使用户能够通过简单的配置调用不同大模型的能力。其主要功能包括智能路由用户请求到不同的AI模型,并提供统一的访问接…...
python成功解决AttributeError: can‘t set attribute ‘lines‘
文章目录 报错信息与原因分析解决方法示例代码代码解释总结 报错信息与原因分析 在使用 matplotlib绘图时,若尝试使用 ax.lines []来清除图表中的线条,会遇到AttributeError: can’t set attribute错误。这是因为 ax.lines是一个只读属性,不…...
宿舍管理系统(servlet+jsp)
宿舍管理系统(servletjsp) 宿舍管理系统是一个用于管理学生宿舍信息的平台,支持超级管理员、教师端和学生端三种用户角色登录。系统功能包括宿舍管理员管理、学生管理、宿舍楼管理、缺勤记录、添加宿舍房间、心理咨询留言板、修改密码和退出系统等模块。宿舍管理员…...
Unity UI 从零到精通 (第30天): Canvas、布局与C#交互实战
Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…...
vue项目打包部署到maven仓库
需要的资源文件,都放在根目录下: 1. versionInfo.js const fs require(fs) const path require(path) const mkdirp require(mkdirp) const spawn require(child_process).spawnconst packageObj require(./package.json) const versionNo packa…...
【力扣】day1
文章目录 27.移除元素26. 删除有序数组的重复项 27.移除元素 26. 删除有序数组的重复项 我们仔细看一下这两道题的最后的返回值,为什么第一题返回slow 而第二题返回slow1 最后的返回值该如何返回绝对不是凭感觉,我们自己分析一下第一个slow,从0位置开始, 遇到val值就开始和fas…...
MySQL:B+树索引
InnoDB索引方案 为了使用二分法快速定位具体的目录项,假设所有目录项都可以在物理存储器上连续存储,有以下问题: InnoDB使用页为管理存储空间的基本单位,最多只能保证16KB的连续存储空间,记录数据量多可能需要非常大…...
如何建立可复用的项目管理模板
建立可复用的项目管理模板能够显著提高项目执行效率、减少重复劳动、确保项目管理标准化。在企业中,项目管理往往涉及多个步骤和多个团队,然而每次开始一个新项目时,如果都从头开始设计流程和文档,势必浪费大量的时间和精力。通过…...
Go:goroutine 和通道
goroutine f() // 等待 f() 返回 go f() // 新建一个调用 f() 的 goroutine,不用等待在 Go 语言里,goroutine 是并发执行的活动单元。与顺序执行程序不同,在有多个 goroutine 的并发程序中,不同函数可同时执行。程序启动时&…...
盛水最多的容器问题详解:双指针法与暴力法的对比与实现
文章目录 问题描述方法探讨方法一:暴力法(Brute Force)思路代码实现复杂度分析 方法二:双指针法(Two Pointers)思路正确性证明代码实现复杂度分析 方法对比总结 摘要 盛水最多的容器(Container …...
VMWare 16 PRO 安装 Rocky8 并部署 MySQL8
VMWare 16 PRO 安装 Rocky8 并部署 MySQL8 一.Rocky OS 下载1.官网 二.配置 Rocky1.创建新的虚拟机2.稍后安装系统3.选择系统模板4.设置名字和位置5.设置大小6.自定义硬件设置核心、运存和系统镜像7.完成 三.启动安装1.上下键直接选择安装2.回车安装3.设置分区(默认…...
日常学习开发记录-slider组件
日常学习开发记录-slider组件 从零开始实现一个优雅的Slider滑块组件前言一、基础实现1. 组件结构设计2. 基础样式实现3. 基础交互实现 二、功能增强1. 添加拖动功能2. 支持范围选择3. 添加垂直模式 三、高级特性1. 键盘操作支持2. 禁用状态 五、使用示例六、总结 从零开始实现…...
AIDL 中如何传递 Parcelable 对象
目录 1. 直接在 AIDL 中定义 Parcelable 对象2. 自定义 Parcelable 对象的传递3. 以 Rect 类为例的 Parcelable 实现4. 注意安全性5. 小结1. 直接在 AIDL 中定义 Parcelable 对象 背景说明 从 Android 10(API 级别 29)开始,AIDL 允许直接在 .aidl 文件中定义 Parcelable 对…...
LVGL实战训练——计算器实现
目录 一、简介 二、部件知识 2.1 按钮矩阵部件(lv_btnmatrix) 2.1.1 按钮矩阵部件的组成 2.1.2 按钮文本设置 2.1.3 按钮索引 2.1.4 按钮宽度 2.1.5 按钮属性 2.1.6 按钮互斥 2.1.7 按钮文本重着色 2.1.8 按钮矩阵部件的事件 2.1.9 按钮矩阵部件的 API 函数 2.2…...
代码随想录算法训练营Day30
力扣452.用最少数量的箭引爆气球【medium】 力扣435.无重叠区间【medium】 力扣763.划分字母区间【medium】 力扣56.合并区间【medium】 一、力扣452.用最少数量的箭引爆气球【medium】 题目链接:力扣452.用最少数量的箭引爆气球 视频链接:代码随想录 题…...
AIDL 语言简介
目录 软件包类型注释导入AIDL 的后端AIDL 语言大致上基于 Java 语言。AIDL 文件不仅定义了接口本身,还会定义这个接口中用到的数据类型和常量。 软件包 每个 AIDL 文件都以一个可选软件包开头,该软件包与各个后端中的软件包名称相对应。软件包声明如下所示: package my.pac…...
经典算法 判断一个图中是否有环
判断一个图中是否有环 问题描述 给一个以0 0结尾的整数对列表,除0 0外的每两个整数表示一条连接了这两个节点的边。假设节点编号不超过100000大于0。你只要判断由这些节点和边构成的图中是否存在环。存在输出YES,不存在输出NO。 输入样例1 6 8 5 3 …...
Transformer-PyTorch实战项目——文本分类
Transformer-PyTorch实战项目——文本分类 ———————————————————————————————————————————— 【前言】 这篇文章将带领大家使用Hugging Face里的模型进行微调,并运用在我们自己的新项目——文本分类中。需要大家提前下…...
Linux-服务器负载评估方法
在 Linux 服务器中,top 命令显示的 load average(平均负载)反映了系统在特定时间段内的负载情况。它通常显示为三个数值,分别代表过去 1 分钟、5 分钟和 15 分钟的平均负载。 1. 什么是 Load Average? Load average …...
Transformer编程题目,结合RTX 3060显卡性能和市场主流技术
以下是10道针对4年经验开发者的Transformer编程题目,结合RTX 3060显卡性能和市场主流技术,每题包含模型选择和实现逻辑描述: 题目1:医疗报告结构化提取 模型选择:BioBERT-base 要求: 开发从PDF医疗报告中提…...
Web三漏洞学习(其二:sql注入)
靶场:NSSCTF 、云曦历年考核题 二、sql注入 NSSCTF 【SWPUCTF 2021 新生赛】easy_sql 这题虽然之前做过,但为了学习sql,整理一下就再写一次 打开以后是杰哥的界面 注意到html网页标题的名称是 “参数是wllm” 那就传参数值试一试 首先判…...
VLAN的知识
1.什么是VLAN? VLAN是虚拟局域网,逻辑隔离广播域和网络区域 是一种通过将局域网内的设备逻辑地划分为一个个网络的技术 2.对比逻辑网络分割和物理网络分割? 逻辑网络分割是VLAN,隔离广播域和网络区域 物理网络分割是路由&…...
RFID 赋能部队智能物联网仓储建设:打造信息化高效解决方案
在当今军事现代化进程的宏大背景下,部队后勤保障工作无疑占据着举足轻重的地位,而仓储管理作为其中的核心环节,更是至关重要。传统的仓储管理模式在面对当下物资种类繁杂、数量庞大的现状时,已显得力不从心,效率低下、…...
结构型屏蔽在高频电子设备中的应用与优化
在当今高度电子化的时代,随着电子产品工作频率不断提高,设备内部温度上升,电磁环境日趋复杂,电磁兼容(EMC)问题成为设计和制造过程中必须重点解决的问题。EMC不仅关系到设备自身的稳定运行,更涉…...
【教程】Ubuntu修改ulimit -l为unlimited
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 问题描述 解决方法一 解决方法二 解决方法三 (终极) 问题描述 查系统资源限制 ulimit -l如果返回的是 64 或其他较小值,那么RDM…...
【HDFS】BlockPlacementPolicyRackFaultTolerant#getMaxNode方法的功能及具体实例
方法参数说明: numOfChosen:已经选择的节点数numOfReplicas:还需要选择的副本数方法的返回值是一个长度为2的数组:[调整后的要选出多少个节点(不包括已经选择的), 每个机架最大能选择的节点数] @Overrideprotected int[] getMaxNodesPerRack(int numOfChosen, int numOfR…...
水污染治理(生物膜+机器学习)
文章目录 **1. 水质监测与污染预测****2. 植物-微生物群落优化****3. 系统设计与运行调控****4. 维护与风险预警****5. 社区参与与政策模拟****挑战与解决思路****未来趋势** 前言: 将机器学习(ML)等人工智能技术融入植树生物膜系统ÿ…...
数模小白变大神的日记2025.4.15日
分工 1.论文:mathtype (Latex) 2.建模;相应的建模知识与撰写方法,写摘要 3.编程:matlab、SPSs、(Python) 评价模型 1. 层次分析法 ①层次分析法是一种多目标、多准则的决策问题 ②层次分析法是一种主观加权法 ③层次分析法通过以下步骤实现: 1.构…...
STM32提高篇: 以太网通讯
STM32提高篇: 以太网通讯 一.以太网通讯介绍二.W5500芯片介绍1.W5500芯片特点2.W5500应用目标3.接入框图 三.驱动移植四.tcp通讯五.udp通讯六.http_server 一.以太网通讯介绍 以太网(Ethernet)是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以…...
4-15记录(冒泡排序,快速选择排序)
算法稳定 简单选择排序的实质就是最后一个和第一个比较,小,就换位置,然后继续用最后一个数字和第二个比较,以此类推。 但是算法不稳定,本来下划线的2在后面,但是经过算法后去了前面 快速排序 实现过程&am…...
Ubuntu系统18.04更新驱动解决方法
原始是:ubuntu18.04里面的驱动是470,对应cuda11.4 现在需要更新为525,对应cuda为12.0 实现: 1、打开终端 Ctrl Alt T2、使用 lspci 命令(快速查看显卡型号) lspci | grep -i vga3、终端输入 ubuntu-d…...
Rocky Linux 9.x 基于 kubeadm部署k8s
搭建集群使用docker下载K8s,使用一主两从模式 主机名IP地址k8s- master192.168.1.141k8s- node-1192.168.1.142k8s- node-2192.168.1.143 一:准备工作 VMware Workstation Pro新建三台虚拟机Rocky Linux 9(系统推荐最小化安装) …...
MATLAB程序实现了一个物流配送优化系统,主要功能是通过遗传算法结合四种不同的配送策略,优化快递订单的配送方案
%% 主函数部分 % function main()clear; clc; close all;% 生成或加载算例 filename = D:\快递优化\LogisticsInstance.mat; if ~exist(filename, file)instance = generate_instance();save(filename, -struct, instance); elseinstance = load(filename); end% 遗传算法参数配…...
利用宝塔面板搭建RustDesk服务
一、介绍 1.1官网 https://rustdesk.com/ 1.2github仓库 https://github.com/rustdesk/rustdesk 1.3特点 RustDesk 支持多种操作系统,包括 Windows、macOS、Linux、Android 和 iOS。它甚至提供网页版客户端,可以在浏览器中直接使用。 用户可以通过…...
前端与Java后端交互出现跨域问题的14种解决方案
跨域问题是前端与后端分离开发中的常见挑战,以下是14种完整的解决方案: 1 前端解决方案( 开发环境代理) 1.1 Webpack开发服务器代理 // vue.config.js 或 webpack.config.js module.exports {devServer: {proxy: {/api: {target: http://localhost:8…...
PBKDF2全面指南(SpringBoot实现版)
文章目录 第一部分:PBKDF2基础概念1. 什么是PBKDF2?2. 为什么需要PBKDF2?3. PBKDF2的工作原理4. PBKDF2与其他密码散列函数的比较第二部分:在Java和SpringBoot中使用PBKDF21. Java内置的PBKDF2支持2. SpringBoot中集成PBKDF22.1 添加依赖2.2 配置PBKDF2密码编码器2.3 自定义…...