Linux多进程和多线程(七)进程间通信-信号量
进程间通信之信号量
资源竞争
多个进程竞争同一资源时,会发生资源竞争。
资源竞争会导致进程的执行出现不可预测的结果。
临界资源
不允许同时有多个进程访问的资源, 包括硬件资源 (CPU、内存、存储器以及其他外
围设备) 与软件资源(共享代码段、共享数据结构)
临界区
多个进程共享的资源被称为临界资源,
这些资源被保护在一个临界区中,
只有进入临界区的进程才能访问临界资源。
信号量
信号量是一种进程间通信机制,用于协调对共享资源的访问。
多进程对stdout资源的竞争
//多进程对stdout资源的竞争#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(){pid_t cpid;cpid = fork();//创建子进程if(cpid < 0){printf("fork error\n");//fork失败exit(EXIT_FAILURE);//EXIT_FAILURE表示程序运行失败} else if(cpid == 0){//子进程while(1){printf("------------------------\n");printf("C Start.\n");sleep(1);printf("C End.\n");printf("------------------------\n");}} else{//父进程while(1){printf("------------------------\n");printf("P Start.\n");sleep(1);printf("P End.\n");printf("------------------------\n");}wait(NULL); //等待子进程结束}return 0;
}
代码的输出混乱:
------------------------
P Start.
------------------------
C Start.
P End.
------------------------
C End.
------------------------
------------------------
P Start.
------------------------
C Start.
P End.
C End.
------------------------
------------------------
同步和互斥
互斥
互斥是指进程独占资源,使得其他进程无法访问该资源。
同步
同步是指进程间通信,用于协调进程的执行。
同步在互斥的基础上增加了进程对临界资源的访问顺序
进程主要的同步与互斥手段是信号量
信号量
信号量,由内核维护的整数,其值被限制为大于或等于0;
信号可以执行一下操作:
- 将信号量设置成一个具体的值;
- 在信号量当前的基础上加上一个数值;
- 在信号量当前值的基础上减上一个数值;
- 等待信号量的值为0;
一般信号量分为
- 二值信号量:一般指的是信号量值为1,可以理解为只对应一个资源
- 计数信号量:一般指的是值大于等于2,可以理解为对应多个资源
在linux系统中使用ipcs -s 查询系统中信号量
创建信号量集合
调用 semget() 函数
函数头文件:
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>int semget(key_t key, int nsems, int semflg);
函数功能:创建一个信号量集合;
函数参数:
- key: 信号量集合的键值, 用于标识信号量集合;由ftok()函数生成;
- nsems: 信号量集合中信号量的个数;
- semflg: 信号量集合的标志位, 用于设置信号量集合的属性;
-
- IPC_CREAT: 如果key对应的信号量集合不存在, 则创建新的信号量集合;
-
- IPC_EXCL: 如果key对应的信号量集合已经存在, 则返回-1;
-
- 权限标志
函数返回值:
- 成功: 返回信号量集合的ID;
- 失败: 返回-1, 并设置errno;
//多进程对stdout资源的竞争#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>#define MSG_PATH "/home/gopher"
#define MSG_ID 88
int main(){key_t key;//通过文件路径和ID生成key,key= ftok(MSG_PATH,MSG_ID);if(key==-1){printf("ftok()");exit(EXIT_FAILURE);}//创建信号量集合,包含了一个信号量,编号为0int semid=semget(key,1,IPC_CREAT|0666);if(semid==-1){printf("semget()");exit(EXIT_FAILURE);}return 0;
}
创建出一个信号量集合,包含了一个信号量,编号为0
初始化信号量
调用 semctl() 函数
函数头文件:
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>int semctl(int semid, int semnum, int cmd, ... /* arg */ );
函数功能:对信号量集合中的信号量进行操作;根据cmd 决定当前函数的功能;
函数参数:
- semid: 信号量集合的ID;
- semnum: 信号量的编号;编号从0开始;
- cmd: 信号量操作命令;
- SETVAL:设置信号量的值。
- GETPID:返回最后一个执行 semop 操作的进程的PID。
- GETVAL:返回指定信号量的值。
- GETALL:返回信号量集中所有信号量的值。
- GETNCNT:返回正在等待信号量增加的进程数。
- GETZCNT:返回正在等待信号量变为零的进程数。
- SETALL:设置信号量集中所有信号量的值。
- IPC_STAT:获取信号量集的状态信息。
- IPC_SET:设置信号量集的状态信息。
- IPC_RMID:删除信号量集。
- … :是属于可变参参数列表,根据不同的命令有不同的参数;
函数返回值:
-
成功: 根据不同的cmd, 返回不同的结果;
-
GETPID:返回等待最后一个 semop 操作的进程的 PID。
GETVAL:返回指定信号量的值。
ls
GETALL:如果成功,返回 0。GETNCNT:返回正在等待增加信号量值的进程数量。
GETZCNT:返回正在等待信号量值为零的进程数量。
IPC_STAT:如果成功,返回 0。
IPC_SET:如果成功,返回 0。
IPC_RMID:如果成功,返回 0。
SETVAL:如果成功,返回 0。
SETALL:如果成功,返回 0。
-
失败: 返回-1, 并设置errno;
//多进程对stdout资源的竞争#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>#define MSG_PATH "/home/gopher"
#define MSG_ID 88union semun{int val;
};
int main(){key_t key;//通过文件路径和ID生成key,key= ftok(MSG_PATH,MSG_ID);if(key==-1){printf("ftok()");exit(EXIT_FAILURE);}//创建信号量集合,包含了一个信号量,编号为0int semid=semget(key,1,IPC_CREAT|0666);if(semid==-1){printf("semget()");exit(EXIT_FAILURE);}union semun s;//定义一个联合体,用于设置信号量的值s.val=1;//设置信号量的值为1int ret=semctl(semid,0,SETVAL,s);//设置semid信号集中的第编号为0的信号量的值为1if(ret==-1){printf("semctl()");exit(EXIT_FAILURE);}return 0;
}
信号量操作
- 信号量可以进⾏以下操作:
- 对信号量的值加 1
- 对信号量的值减 1
- 等待信号量的值为 0
调用 semop() 函数
函数头文件:
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>int semop(int semid, struct sembuf *sops, size_t nsops);
函数功能:对信号量集合中的信号量进行操作;
函数参数:
- semid: 信号量集合的ID;
- sops: 信号量操作结构体指针
- nsops: 信号量操作结构体的个数;
函数返回值:
- 成功: 返回 0;
- 失败: 返回-1, 并设置errno;
struct sembuf *sops: 信号量操作结构体指针
struct sembuf
{unsigned short int sem_num;//信号量编号,从0开始short int sem_op; //信号量操作//-1:占用资源// +1:释放资源// 0:等待资源short int sem_flg; //信号量操作标志位//IPC_NOWAIT:非阻塞,在信号量的值为0时,立即返回// SEM_UNDO:在进程终止时,会自动释放信号量
};
信号量集合删除
调用 semctl() 函数 ,设置命令为 IPC_RMID
在使用 semctl() 函数删除信号量集合时,需要注意第三个参数会被忽略
信号量互斥应用
使用信号量实现进程间互斥,同一时间只有一个进程访问临界资源
1.创建sem.h
#ifndef _mySEM_H_
#define _mySEM_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>//创建信号量集
int sem_create(int names,unsigned short value[]);
//占用信号量
int sem_p(int semid,int semnum);
//释放信号量
int sem_v(int semid,int semnum);
//删除信号量集
int sem_delete(int semid);#endif /* _SEM_H_ */
2.创建sem.c
#include "sem.h"union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */};//创建信号量集
//@param names 信号量集的个数
//@param value 信号量集的初始值
//@return 成功返回信号量集的id,失败返回-1
int sem_create(int names,unsigned short value[]){key_t key;//创建keykey= ftok(".",88);if (key == -1){perror("ftok");return -1;}//创建信号量集int semid;semid = semget(key,names,IPC_CREAT|0666);//参数:key,信号量集的个数,权限if (semid == -1){perror("semget");return -1;}union semun s; //定义union semuns.array = value;//将value数组赋值给union semun的array成员//初始化信号量集int ret=semctl(semid,0,SETALL,s);//这个操作将value数组中的值设置到信号量集中if (ret == -1){perror("semctl");return -1;}return semid;}//占用信号量
//@param semid 信号量集的id
//@param semnum 信号量的编号
int sem_p(int semid,int semnum){struct sembuf sem_b;//定义一个信号量操作结构体sem_b.sem_num=semnum;//信号量编号sem_b.sem_op= -1;//占用资源sem_b.sem_flg=SEM_UNDO;//在进程终止时,会自动释放信号量//操作1个信号量,如果操作多个信号量,需要创建sembuf结构体的数组int r= semop(semid,&sem_b,1); //失败返回-1,并设置errno return r;
}
//释放信号量
int sem_v(int semid,int semnum){struct sembuf sem_b;//定义一个信号量操作结构体sem_b.sem_num=semnum;//信号量编号sem_b.sem_op= 1;//释放资源sem_b.sem_flg=SEM_UNDO;//在进程终止时,会自动释放信号量int r= semop(semid,&sem_b,1); //操作1个信号量,如果操作多个信号量,需要创建sembuf结构体的数组//失败返回-1,并设置errno return r;
}
//删除信号量集
int sem_delete(int semid){int r= semctl(semid,0,IPC_RMID); //删除信号量集return r;
}
3.创建main.c
// 多进程对stdout资源的竞争#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include "sem.h"
int main()
{int semid;// 信号量IDunsigned short values[] = {1};// 信号量初始值semid = sem_create(1, values);if(semid == -1 ){printf("sem_create error\n");exit(EXIT_FAILURE);}pid_t cpid;// 子进程IDcpid = fork(); // 创建子进程if (cpid < 0){printf("fork error\n"); // fork失败exit(EXIT_FAILURE); // EXIT_FAILURE表示程序运行失败}else if (cpid == 0){ // 子进程while (1){sem_p(semid,0);printf("------------------------\n");printf("C Start.\n");sleep(1);printf("C End.\n");printf("------------------------\n");sem_v(semid,0);}}else{ // 父进程while (1){sem_p(semid,0);printf("------------------------\n");printf("P Start.\n");sleep(1);printf("P End.\n");printf("------------------------\n");sem_v(semid,0);}wait(NULL); // 等待子进程结束}return 0;
}
4.编译运行
------------------------
P Start.
P End.
------------------------
------------------------
C Start.
C End.
------------------------
------------------------
P Start.
P End.
------------------------
------------------------
C Start.
C End.
----------
信号量同步应用
同步在互斥的基础上增加了进程对临界资源的访问顺序
进程主要的同步与互斥手段是信号量
示例:
创建⽗⼦进程,输出 “ABA” 字符串,具体需求如下:
⽗进程 输出 A
⼦进程 输出 B
⽗进程 输出 A ,输出换⾏
能够循环输出 “ABA” 字符
基本思路:
通过创建⼀个信号量集合,包含 2 个信号量,⼀个信号量 编号为 0
(SEM_CONTROL_P)控制⽗进程的运⾏与暂停,⼀个信号量 编号为 1
(SEM_CONTROL_C) 控制⼦进程的运⾏与暂停
// 多进程对stdout资源的竞争#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include "sem.h"#define SEM_C = 1
#define SEM_P = 0
// todo 创建一个信号量集合,集合中两个信号量,信号量0的值是1,信号量1的值是0;
int main()
{int semid; // 信号量IDunsigned short values[2] = {1, 0}; // 信号量初始值// todo 创建一个信号量集合,集合中两个信号量,信号量编号0的值是1,信号量编号1的值是0;semid = sem_create(2, values);if (semid == -1){printf("sem_create error\n");exit(EXIT_FAILURE);}pid_t cpid; // 子进程IDcpid = fork(); // 创建子进程if (cpid < 0){printf("fork error\n"); // fork失败exit(EXIT_FAILURE); // EXIT_FAILURE表示程序运行失败}else if (cpid == 0){ // 子进程while (1){sem_p(semid, 1); //?占用信号量编号1,信号量编号1的值初始是0 ,在这里阻塞,等待父进程操作printf("B");fflush(stdout); // 刷新缓冲sem_v(semid, 0); //!释放信号量编号0,信号量编号0的值 0=>1,此时父进程不再阻塞,第二次占用0}}else{ // 父进程while (1){//@param semid 信号量集的id//@param semnum 信号量的编号sem_p(semid, 0); //?占用信号量编号0,信号量编号0的值 1=>0printf("A");fflush(stdout); // 刷新缓冲sem_v(semid, 1); //?释放信号量编号1,信号量编号1的值 0=>1,此时子进程不再阻塞sem_p(semid, 0); //!第二次占用信号量编号0,信号量编号0的值是0,在这里阻塞,等待子进程的操作printf("A\n");fflush(stdout); // 刷新缓冲sem_v(semid, 0);sleep(1);}wait(NULL); // 等待子进程结束}return 0;
}
0的值 0=>1,此时父进程不再阻塞,第二次占用0}}else{ // 父进程while (1){//@param semid 信号量集的id//@param semnum 信号量的编号sem_p(semid, 0); //?占用信号量编号0,信号量编号0的值 1=>0printf("A");fflush(stdout); // 刷新缓冲sem_v(semid, 1); //?释放信号量编号1,信号量编号1的值 0=>1,此时子进程不再阻塞sem_p(semid, 0); //!第二次占用信号量编号0,信号量编号0的值是0,在这里阻塞,等待子进程的操作printf("A\n");fflush(stdout); // 刷新缓冲sem_v(semid, 0);sleep(1);}wait(NULL); // 等待子进程结束}return 0;
}
相关文章:

Linux多进程和多线程(七)进程间通信-信号量
进程间通信之信号量 资源竞争 多个进程竞争同一资源时,会发生资源竞争。 资源竞争会导致进程的执行出现不可预测的结果。 临界资源 不允许同时有多个进程访问的资源, 包括硬件资源 (CPU、内存、存储器以及其他外 围设备) 与软件资源(共享代码段、共享数据结构) …...

【项目日记(一)】梦幻笔耕-数据层实现
❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ 🚚我的代码仓库: 33的代码仓库🚚 🫵🫵🫵关注我带你了解更多项目内容 目录 1.前言2.后端模块3数据库设计4.mapper实现4.1UserInfoMapper4.2BlogMapper 5.总结 1.…...
ElementUI的中国省市区级联数据插件element-china-area-data
安装 npm install element-china-area-data -S import 使用 import {provinceAndCityData,pcTextArr,regionData,pcaTextArr,codeToText, } from "element-china-area-data"; provinceAndCityData省市二级联动数据,汉字+coderegionData省市区三级联动数据pcTextAr…...
Kotlin算法:把一个整数向上取值为最接近的2的幂指数值
Kotlin算法:把一个整数向上取值为最接近的2的幂指数值 import kotlin.math.ln import kotlin.math.powfun main(args: Array<String>) {val number intArrayOf(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)number.forEach {println("$…...

简单且循序渐进地查找软件中Bug的实用方法
“Bug”这个词常常让许多开发者感到头疼。即使是经验丰富、技术娴熟的开发人员在开发过程中也难以避免遭遇到 Bug。 软件中的故障会让程序员感到挫败。我相信在你的软件开发生涯中,也曾遇到过一些难以排查的问题。软件中的错误可能会导致项目无法按时交付。因此&…...

基于springboot+vue+uniapp的高校宿舍信息管理系统小程序
开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…...

(完整音频)DockerHub、OpenAI、GitCode,脱钩时代,我们该如何自处?
本期主播 朱峰:「津津乐道播客网络」创始人,产品及技术专家。(微博:zhufengme)高春辉:「科技乱炖」主播。“中国互联网站长第一人”,科技、互联网领域的连续创业者。(微博࿱…...

macos 10.15系统下载包,macOS Catalina for mac
macOS Catalina 让你喜欢的种种 Mac 体验都更进一步。你可以领略音乐、播客这两款全新 Mac app 的表演;在 Mac 上畅享各款自己心爱的 iPad app;拿起 iPad 和 Apple Pencil,拓展工作空间,释放创意灵感;再打开那些平时常…...
uni.showShareMenu({}) 和 uni.showShareImageMenu({}) 的区别
ChatGPT uni.showShareMenu({}) 和 uni.showShareImageMenu({}) 是 Uni-app 中两个不同的 API,它们的作用和用法有所不同: uni.showShareMenu({}) 作用:用于显示当前页面的分享菜单,通常显示在页面的右上角(类似于微…...
Spring Boot logback 日志文件配置
引入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>logback-spring.xml 配置 <?xml version"1.0" encoding"UTF-8&quo…...

240705_昇思学习打卡-Day17-基于 MindSpore 实现 BERT 对话情绪识别
240705_昇思学习打卡-Day17-基于 MindSpore 实现 BERT对话情绪识别 近期确实太忙,此处仅作简单记录: 模型简介 BERT全称是来自变换器的双向编码器表征量(Bidirectional Encoder Representations from Transformers),…...

图像处理调试软件推荐
对于图像处理的调试,使用具有图形用户界面(GUI)且支持实时调整和预览的图像处理软件,可以大大提高工作效率。以下是几款常用且功能强大的图像处理调试软件推荐: ImageJ/FijiMATLABOpenCV with GUI LibrariesNI Vision …...

Mybatis实现RBAC权限模型查询
RBAC权限模型 Role-Based Access Control,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。 简单来说,就是通过将权限分配给➡角色,再将角色分配给➡用…...

最短路算法——差分约束
差分约束 (1) 求不等式组的可行解 源点:从源点出发,一定可以走到所有的边求可行解步骤: 先将每个不等式 x i ≤ x j c x_i \le x_j c xi≤xjc,转化成一条从 s j s_j sj走到 s i s_i si,长度为 c k c_k ck 的一条边找…...

Log4j日志框架讲解(全面,详细)
目录 Log4j概述 log4j的架构(组成) Loggers Appenders Layouts 快速入门 依赖 java代码 日志的级别 log4j.properties 自定义Logger 总结: Log4j概述 Log4j是Apache下的一款开源的日志框架,通过在项目中使用 Log4J&…...
LeetCode 35, 242, 994
目录 35. 搜索插入位置题目链接标签思路代码 242. 有效的字母异位词题目链接标签思路代码 994. 腐烂的橘子题目链接标签思路代码 35. 搜索插入位置 题目链接 35. 搜索插入位置 标签 数组 二分查找 思路 本题与 704. 二分查找 十分相似,只不过本题在找不到 tar…...

ctfshow-web入门-文件包含(web87)巧用 php://filter 流绕过死亡函数的三种方法
目录 方法1:php://filter 流的 base64-decode 方法 方法2:通过 rot13 编码实现绕过 方法3:通过 strip_tags 函数去除 XML 标签 除了替换,新增 file_put_contents 函数,将会往 $file 里写入 <?php die(大佬别秀了…...
adb shell ps -T打印出来参数的含义,以及D,T,Z代表的状态含义是什么?
在Android系统中,使用adb shell ps命令可以查看当前系统中运行的进程信息。当你添加-T选项时(注意,标准的ps命令在Android的adb shell中可能不直接支持-T选项,这通常与Linux中的ps命令略有不同),你可能是想…...
leetcode77组合——经典回溯算法
本文主要讲解组合的要点与细节,以及回溯算法的解题步骤,按照步骤思考更方便理解 c和java代码如下,末尾 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 具体要点: …...

springcloud-alibba之FeignClient
代码地址:springcloud系列: springcloud 组件分析拆解 1.FeignClient的集成 springboot版本:3.1.5 springcloud组件版本:2022.0.4 nacos客户端的版本:2.3.2 1.引pom 这里引入了nacos和feginclient的版本 <dependency>…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...