【Linux】进程通信篇Ⅱ:共享内存、消息队列、信号量
文章目录
- 一、共享内存
- 1.1 一些接口
- 1. shmget 函数:申请一个 system v 的共享内存块
- 2. ftok 函数:设置唯一标识码
- 3. shmctl 函数:控制 system v 的共享内存块(可以删除、查看...)
- 4. shmat 函数:将进程与共享内存块 关联\ 挂接(attach)
- 5. shmdt 函数:将进程与共享内存块 去关联(detach)
- 1.2 一些命令
- 1. ipcs - - 查看三种 ipc 资源
- 2. ipcrm -- 删除某种 ipc 资源
- 1.3 结论
- 二、消息队列
- 1. msgget 函数:创建消息队列
- 2. msgctl 函数
- 3. msgsnd 和 msgrcv 函数,发送和接收消息
- 三、信号量
- 1. semget
- 2. semctl 函数:可以获取信号量的相关属性
- 3. semop 函数:对信号量进行操作
- 总结:
一、共享内存
我们知道,进程间通信的本质就是:让不同的进程,看到同一份资源
这里要介绍的同一份资源就是:内存块,即 共享内存(shared memory,简写为 shm)
- 共享内存的原理:
- 1.创建(key 和 共享内存)
- 2.关联进程 和 取消关联
- 3.释放共享内存
内存中的每块共享内存,会有一个 struct shm 结构体,里面放着共享内存的全部属性,OS 通过这个结构体建立链表关系来对所有的共享内存进行管理,就等于把管理 shm 的问题转化成了管理链表的问题。
故:
共享内存
=
共享内存的内核数据结构 (伪代码:struct shm)
+
真正开辟的内存空间
1.1 一些接口
1. shmget 函数:申请一个 system v 的共享内存块
头文件:
#include <sys/ipc.h>
#include <sys/shm.h>// umask的头文件如下
#include <sys/types.h>
#include <sys/stat.h>
int shmget(key_t key, size_t size, int shmflg);
参数 key:
- 使用
ftok函数设置的唯一标识码,他虽由用户设置,却是在内核中使用的
参数 size
- 需要申请共享内存块的大小,单位为字节,不足 PAGE 页(4KB)时,会向上对齐到 PAGE 页
参数 shmflg:
选项 IPC_CREAT and IPC_EXCL
单独使用 IPC_CREAT:创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就获取已经存在的共享内存并返回。
IPC_CREAT | IPC_EXCL :IPC_EXCL 必须要配合 IPC_CREAT 使用,创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就出错返回
意味着,一起使用时,如果创建成功,对应的shm,一定是最新的!IPC_CREAT | IPC_EXCL | 0666 :上面的基础上,添加权限(可以配合函数 umask(0) 使用)
返回值:
- 成功会返回一个共享内存标识符,失败返回 -1
2. ftok 函数:设置唯一标识码
头文件
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
参数 pathname
- 用户设置的路径
参数 proj_id
- 用户设置的项目 id
返回值:
- 根据用户传入的参数,结合一定的算法,返回一个冲突概率很低的值。ket_t 就是一个 32 位的整数,是对 int 的封装
3. shmctl 函数:控制 system v 的共享内存块(可以删除、查看…)
头文件
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数 shmid
- 需要的共享内存块的 shmid
参数 cmd:
- 选项 IPC_STAT:把用户传入 shmid 的相应内核数据结构信息复制到 buf 中(在调用者有读权限的情况下,才能成功)
- 选项 IPC_RMID:删除 shmid 为传入值的共享内存块
输出型参数 buf:
- 需要得到 ipc 信息时传一个相应类型的值用来接收结果
返回值:
- 失败返回 -1,成功则根据 cmd 传入的选项返回对应的值
//The buf argument is a pointer to a shmid_ds structure, defined in <sys/shm.h> as follows:struct shmid_ds {struct ipc_perm shm_perm; /* Ownership and permissions */size_t shm_segsz; /* Size of segment (bytes) */time_t shm_atime; /* Last attach time */time_t shm_dtime; /* Last detach time */time_t shm_ctime; /* Last change time */pid_t shm_cpid; /* PID of creator */pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */shmatt_t shm_nattch; /* No. of current attaches */...};//The ipc_perm structure is defined as follows (the highlighted fields are settable using IPC_SET):struct ipc_perm {key_t __key; /* Key supplied to shmget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq; /* Sequence number */};
4. shmat 函数:将进程与共享内存块 关联\ 挂接(attach)
头文件
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数 shmid
- 需要的共享内存块的 shmid
参数 shmaddr:
- 用户可以选择虚拟地址作为共享内存块的起始地址
- 用户一般不定义,设为 nullptr 让 OS 自主定义即可
参数 shmflg:
- 选项 SHM_RDONLY:只读
- 0:可以读写
返回值:
- 挂接成功,返回共享内存块的虚拟地址的起始地址
5. shmdt 函数:将进程与共享内存块 去关联(detach)
头文件
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
参数 shmaddr:
- 共享内存块的起始地址
返回值:
- 去关联成功返回 0,失败返回 -1
1.2 一些命令
1. ipcs - - 查看三种 ipc 资源
ipcs 就是进程间通信(ipc)资源
ipcs:可以查看 消息队列、共享内存亏块、信号量
-m:查看 共享内存块(memory)
-s:查看 信号量(semaphore)
perms:权限
nattach:当前 ipc 挂接的进程数
2. ipcrm – 删除某种 ipc 资源
ipcrm:删除一个 消息队列、共享内存亏块、信号量
-m:删除一个共享内存块,后接 shmid
1.3 结论
-
两个进程管道通信一次,需要进行两次复制。而共享内存间的通信,可以让进程们直接在自己映射的地址空间中访问,减少了拷贝次数()
-
管道单方面关闭读写端会有相应的保护,而共享内存没有保护机制(同步互斥)。管道通过系统接口通信,共享内存直接通信
-
互斥:任何一个时刻,都只允许一个执行流在进行共享资源的访问,叫做加锁
-
我们把任何一个时刻,都只允许一个执行流在进行访问的共享资源,叫做 临界资源。凡是访问临界资源的代码,叫做临界区,控制进出临界区的手段造就了临界资源。
二、消息队列
1. msgget 函数:创建消息队列
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
参数 key:
- 使用
ftok函数设置的唯一标识码
参数 msgflg:
选项 IPC_CREAT and IPC_EXCL
单独使用 IPC_CREAT:创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就获取已经存在的共享内存并返回。
IPC_CREAT | IPC_EXCL :IPC_EXCL 必须要配合 IPC_CREAT 使用,创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就出错返回
意味着,一起使用时,如果创建成功,对应的shm,一定是最新的!IPC_CREAT | IPC_EXCL | 0666 :上面的基础上,添加权限(可以配合函数 umask(0) 使用)
返回值:
- 成功则返回消息队列的标识符
2. msgctl 函数
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数 msqid
- 需要的消息队列的 msqid
参数 cmd:
- 选项 IPC_STAT:把用户传入 msqid 的相应内核数据结构信息复制到 buf 中(在调用者有读权限的情况下,才能成功)
- 选项 IPC_RMID:删除 msqid 为传入值的共享内存块
输出型参数 buf:
- 需要得到 ipc 信息时传一个相应类型的值用来接收结果
返回值:
- 成功返回 >= 0 的值,失败返回 -1
The msqid_ds data structure is defined in <sys/msg.h> as follows:struct msqid_ds {struct ipc_perm msg_perm; /* Ownership and permissions */time_t msg_stime; /* Time of last msgsnd(2) */time_t msg_rtime; /* Time of last msgrcv(2) */time_t msg_ctime; /* Time of last change */unsigned long __msg_cbytes; /* Current number of bytes inqueue (nonstandard) */msgqnum_t msg_qnum; /* Current number of messagesin queue */msglen_t msg_qbytes; /* Maximum number of bytesallowed in queue */pid_t msg_lspid; /* PID of last msgsnd(2) */pid_t msg_lrpid; /* PID of last msgrcv(2) */};The ipc_perm structure is defined as follows (the highlighted fields are settable using
IPC_SET):struct ipc_perm {key_t __key; /* Key supplied to msgget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions */unsigned short __seq; /* Sequence number */};
3. msgsnd 和 msgrcv 函数,发送和接收消息
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数 msqid:
- 发送和接收访问的同一个消息队列
参数 msgp:
- 发送或接收的数据块
参数 msgsz:
- 发送或接收数据块的大小
参数 msgflg:
- 选项,一般填 0 即可
参数 msgtyp:
- msgbuf 里面的 mtype
// The msgp argument is a pointer to caller-defined structure of the following general form:struct msgbuf {long mtype; /* message type, must be > 0 */char mtext[1]; /* message data */
};
三、信号量
信号量 / 信号灯(semaphore),本质 就是一个计数器,是一个描述资源数量的计数器。
举个例子:
-
比如我们任何一个执行流,像访问临界资源中的一个子资源的时候,不能直接访问,需要 先申请信号量资源(P操作),此时 count-- 。只要申请信号量成功,未来就一定能拿到一个子资源。(类似摇号)
-
然后进入进程自己的临界区,访问对应的临界资源。
-
使用完成后,进程释放信号量资源(V操作),只要将计数器增加 count++,就表示将我们对应的资源进行了归还。
至此,进程通过执行代码来申请,意味着,所有进程都得先看到信号量,信号量就是一个共享资源。(信号量保护共享资源,自己却又是一个共享资源)
故,信号量必须保证自己的 ++ - - 是原子的
也,信号量被归类到了进程间通信
信号量部分未完待续~
1. semget
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
参数 key:
- 使用
ftok函数设置的唯一标识码,他虽由用户设置,却是在内核中使用的
参数 nsems:
- 申请信号量的个数(叫做信号量集)
参数 semflg:
选项 IPC_CREAT and IPC_EXCL
单独使用 IPC_CREAT:创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就获取已经存在的共享内存并返回。
IPC_CREAT | IPC_EXCL :IPC_EXCL 必须要配合 IPC_CREAT 使用,创建一个共享内存,如果共享内存不存在,就创建,如果已经存在就出错返回
意味着,一起使用时,如果创建成功,对应的shm,一定是最新的!IPC_CREAT | IPC_EXCL | 0666 :上面的基础上,添加权限(可以配合函数 umask(0) 使用)
返回值:
- 成功会返回一个信号量计数器标识符,失败返回 -1
2. semctl 函数:可以获取信号量的相关属性
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);
参数 semid:
- 需要的信号量的semid
参数 semnum:
- 信号量编号
参数 cmd:
- 选项 IPC_STAT:把用户传入 msqid 的相应内核数据结构信息复制到 buf 中(在调用者有读权限的情况下,才能成功)
- 选项 IPC_RMID:删除 msqid 为传入值的共享内存块
返回值:
- 成功返回 >= 0 的值,失败返回 -1
//This function has three or four arguments, depending on cmd. When there are four, the
//fourth has the type union semun. The calling program must define this union as follows: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) */};//The semid_ds data structure is defined in <sys/sem.h> as follows:struct semid_ds {struct ipc_perm sem_perm; /* Ownership and permissions */time_t sem_otime; /* Last semop time */time_t sem_ctime; /* Last change time */unsigned long sem_nsems; /* No. of semaphores in set */};//The ipc_perm structure is defined as follows (the highlighted fields are settable usingIPC_SET):struct ipc_perm {key_t __key; /* Key supplied to semget(2) */uid_t uid; /* Effective UID of owner */gid_t gid; /* Effective GID of owner */uid_t cuid; /* Effective UID of creator */gid_t cgid; /* Effective GID of creator */unsigned short mode; /* Permissions */unsigned short __seq; /* Sequence number */};
3. semop 函数:对信号量进行操作
头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数 sops:
- 需要用户自己定义后传入,设置结构体内容,以此达到对信号量的 PV 操作等等
//Each semaphore in a System V semaphore set has the following associated values:unsigned short semval; /* semaphore value */unsigned short semzcnt; /* # waiting for zero */unsigned short semncnt; /* # waiting for increase */pid_t sempid; /* ID of process that did last op *///semop() performs operations on selected semaphores in the set indicated by semid.
//Each of the nsops elements in the array pointed to by sops specifies an operation to be performed on a single semaphore.
//The elements of this structure are of type struct sembuf, containing the following members:unsigned short sem_num; /* semaphore number */short sem_op; /* semaphore operation */short sem_flg; /* operation flags */
总结:
共享内存、消息队列、信号量 这三种 ipc 都有各自的内核数据结构体,而结构体的第一个成员都是 struct ipc_perm xx_perm。
可以理解为 OS 将这三种 ipc 都放进了一个 struct ipc_perm* ipc_id_arr[] 指针数组中进行管理(这里只是做理解解释,实际上更复杂)。
OS 通过指针,可以找到每个结构体(同时也是每个结构的第一个成员,即 struct ipc_perm xx_perm),在其中找到 key 值就可以确定。
要访问里面的内容时,以共享内存举例
((struct shmid_ds*)ipc_id_arr[n])->other...
对指针进行强转,就可以访问到其中内容了,这也是一种多态。
相关文章:
【Linux】进程通信篇Ⅱ:共享内存、消息队列、信号量
文章目录 一、共享内存1.1 一些接口1. shmget 函数:申请一个 system v 的共享内存块2. ftok 函数:设置唯一标识码3. shmctl 函数:控制 system v 的共享内存块(可以删除、查看...)4. shmat 函数:将进程与共享…...
8.14 校招 内推 面经
绿泡泡: neituijunsir 交流裙,内推/实习/校招汇总表格 1、半导体芯片一周资讯 - 小米OPPO之后,星纪魅族调整芯片业务,今年应届生或被全部优化,英伟达2024推出比H100更快的芯片 半导体芯片一周资讯 - 小米OPPO之后&…...
阿里云服务器安装部署Docker使用教程
本文阿里云百科分享如何在云服务ECS实例上,部署并使用Docker。Docker是一款开源的应用容器引擎,具有可移植性、可扩展性、高安全性和可管理性等优势。开发者可将应用程序和依赖项打包到一个可移植的容器中,快速发布到Linux机器上并实现虚拟化…...
WebRTC | ICE详解
目录 一、Candidate种类与优先级 二、ICE策略 1. iceServers 2. iceTransportPolicy 三、P2P连接 1.Nat类型 (1)完全锥型NAT (2)IP限制锥型NAT (3)端口限制锥型NAT (4)对称…...
网络设备(防火墙、路由器、交换机)日志分析监控
外围网络设备(如防火墙、路由器、交换机等)是关键组件,因为它们控制进出公司网络的流量。因此,监视这些设备的活动有助于 IT 管理员解决操作问题,并保护网络免受攻击者的攻击。通过收集和分析这些设备的日志来监控这些…...
2023年国赛数学建模思路 - 复盘:人力资源安排的最优化模型
文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 描述 …...
Compute shader SV 理解图
本图转子:【Computeshader】个人总结_蒋伟博的博客-CSDN博客...
生信豆芽菜-多种算法计算免疫浸润
网址:http://www.sxdyc.com/immuneInfiltration 一、使用方法 1、数据准备 一个全编码蛋白的表达谱基因,其中行为基因,列为样本 第一列为基因为行名,不能重复 2、选择计算的方法(这里提供了5种免疫计算的方法&#x…...
逆向破解学习-单机斗地主
试玩 破解思路 9000 是成功的代码 Hook代码 import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class HookComJuneGameDouDiZhu extends HookImpl{ Override p…...
matplotlib绘制位置-时序甘特图
文章目录 1 前言2 知识点2.1 matplotlib.pyplot.barh2.2 matplotlib.legend的handles参数 3 代码实现4 绘制效果5 总结参考 1 前言 这篇文章的目的是,总结记录一次使用matplotlib绘制时序甘特图的经历。之所以要绘制这个时序甘特图,是因为22年数模研赛C…...
数据库概述、部署MySQL服务、必备命令、密码管理、安装图形软件、SELECT语法 、筛选条件
Top NSD DBA DAY01 案例1:构建MySQL服务器案例2:密码管理案例3:安装图形软件案例4:筛选条件 1 案例1:构建MySQL服务器 1.1 问题 在IP地址192.168.88.50主机和192.168.88.51主机上部署mysql服务练习必备命令的使用 …...
概率论与数理统计:第四章:随机变量的数字特征
文章目录 Ch4. 随机变量的数字特征1. 数学期望E(X)(1)数学期望的概念1.离散型①一维离散型随机变量X的数学期望: E X EX EX②一维离散型随机变量的函数的期望: E [ g ( X ) ] E[g(X)] E[g(X)]③二维离散型随机变量的函数的期望: E [ g ( X , …...
解决饿了么ui的对话框缩放和移动
import Vue from "vue";// v-dialogDrag: 弹窗拖拽水平方向伸缩 /** 使用方法* 将以下代码复制到一个js文件中,然后在入口文件main.js中import引入即可;* 给elementUI的dialog上加上 v-dialogDrag 指令就可以实现弹窗的全屏和拉伸了。* 给…...
Linux 中复制文件并保持修改时间等属性
一、遇到的问题 Linux使用cp命令复制文件备份时,发现文件的修改时间变成当前时间了,想要保留备份文件原有的修改时间及其它文件属性。 二、实现 1、cp命令 在 Linux 中,你可以使用 cp 命令来复制文件,并通过 -p 或 --preserve…...
Hugging News #0814: Llama 2 学习资源大汇总
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等,我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息࿰…...
可视化绘图技巧100篇进阶篇(五)-阶梯线图(Step Chart)
目录 前言 图表类型特征 适用场景 图例 绘图工具及代码实现 ECharts SMARTBI...
GPT带我学-设计模式-命令模式
1 你知道设计模式的命令模式吗 是的,我知道设计模式中的命令模式。命令模式是一种行为型设计模式,它将请求封装成一个对象,从而允许使用不同的请求、队列或日志来参数化其他对象。命令模式还支持撤销操作,并且可以提供事务的实现…...
互联网发展历程:跨越远方,路由器的启示
互联网的蓬勃发展,一直在追求更广阔的连接,更遥远的距离。然而,在早期的网络中,人们面临着连接距离有限的问题。一项重要的技术应运而生,那就是“路由器”。 连接受限的问题:距离有限 早期的网络受限于直接…...
postman入门基础 —— 接口测试流程
一、编写接口测试计划 接口测试计划和功能测试计划目标一致,都是为了确认需求、确定测试环境、确定测试方法,为设计测试用例做准备,初步制定接口测试进度方案。一般来说,接口测试计划包括概述、测试资源、测试功能、测试重点、测试…...
springcloud+nacos实现灰度发布
灰度发布 gateway网关实现灰度路由 灰度发布实体 package com.scm.boss.common.bean;import lombok.Data; import lombok.experimental.Accessors;import java.io.Serializable;/*** 灰度发布实体*/ Data Accessors(chain true) public class GrayBean implements Serializ…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
