当前位置: 首页 > news >正文

【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. 两个进程管道通信一次,需要进行两次复制。而共享内存间的通信,可以让进程们直接在自己映射的地址空间中访问,减少了拷贝次数()

  2. 管道单方面关闭读写端会有相应的保护,而共享内存没有保护机制(同步互斥)。管道通过系统接口通信,共享内存直接通信

  3. 互斥:任何一个时刻,都只允许一个执行流在进行共享资源的访问,叫做加锁

  4. 我们把任何一个时刻,都只允许一个执行流在进行访问的共享资源,叫做 临界资源。凡是访问临界资源的代码,叫做临界区,控制进出临界区的手段造就了临界资源。



二、消息队列

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 函数&#xff1a;申请一个 system v 的共享内存块2. ftok 函数&#xff1a;设置唯一标识码3. shmctl 函数&#xff1a;控制 system v 的共享内存块&#xff08;可以删除、查看...&#xff09;4. shmat 函数&#xff1a;将进程与共享…...

8.14 校招 内推 面经

绿泡泡&#xff1a; neituijunsir 交流裙&#xff0c;内推/实习/校招汇总表格 1、半导体芯片一周资讯 - 小米OPPO之后&#xff0c;星纪魅族调整芯片业务&#xff0c;今年应届生或被全部优化&#xff0c;英伟达2024推出比H100更快的芯片 半导体芯片一周资讯 - 小米OPPO之后&…...

阿里云服务器安装部署Docker使用教程

本文阿里云百科分享如何在云服务ECS实例上&#xff0c;部署并使用Docker。Docker是一款开源的应用容器引擎&#xff0c;具有可移植性、可扩展性、高安全性和可管理性等优势。开发者可将应用程序和依赖项打包到一个可移植的容器中&#xff0c;快速发布到Linux机器上并实现虚拟化…...

WebRTC | ICE详解

目录 一、Candidate种类与优先级 二、ICE策略 1. iceServers 2. iceTransportPolicy 三、P2P连接 1.Nat类型 &#xff08;1&#xff09;完全锥型NAT &#xff08;2&#xff09;IP限制锥型NAT &#xff08;3&#xff09;端口限制锥型NAT &#xff08;4&#xff09;对称…...

网络设备(防火墙、路由器、交换机)日志分析监控

外围网络设备&#xff08;如防火墙、路由器、交换机等&#xff09;是关键组件&#xff0c;因为它们控制进出公司网络的流量。因此&#xff0c;监视这些设备的活动有助于 IT 管理员解决操作问题&#xff0c;并保护网络免受攻击者的攻击。通过收集和分析这些设备的日志来监控这些…...

2023年国赛数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …...

Compute shader SV 理解图

本图转子&#xff1a;【Computeshader】个人总结_蒋伟博的博客-CSDN博客...

生信豆芽菜-多种算法计算免疫浸润

网址&#xff1a;http://www.sxdyc.com/immuneInfiltration 一、使用方法 1、数据准备 一个全编码蛋白的表达谱基因&#xff0c;其中行为基因&#xff0c;列为样本 第一列为基因为行名&#xff0c;不能重复 2、选择计算的方法&#xff08;这里提供了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 前言 这篇文章的目的是&#xff0c;总结记录一次使用matplotlib绘制时序甘特图的经历。之所以要绘制这个时序甘特图&#xff0c;是因为22年数模研赛C…...

数据库概述、部署MySQL服务、必备命令、密码管理、安装图形软件、SELECT语法 、筛选条件

Top NSD DBA DAY01 案例1&#xff1a;构建MySQL服务器案例2&#xff1a;密码管理案例3&#xff1a;安装图形软件案例4&#xff1a;筛选条件 1 案例1&#xff1a;构建MySQL服务器 1.1 问题 在IP地址192.168.88.50主机和192.168.88.51主机上部署mysql服务练习必备命令的使用 …...

概率论与数理统计:第四章:随机变量的数字特征

文章目录 Ch4. 随机变量的数字特征1. 数学期望E(X)(1)数学期望的概念1.离散型①一维离散型随机变量X的数学期望&#xff1a; E X EX EX②一维离散型随机变量的函数的期望&#xff1a; E [ g ( X ) ] E[g(X)] E[g(X)]③二维离散型随机变量的函数的期望&#xff1a; E [ g ( X , …...

解决饿了么ui的对话框缩放和移动

import Vue from "vue";// v-dialogDrag: 弹窗拖拽水平方向伸缩 /** 使用方法* 将以下代码复制到一个js文件中&#xff0c;然后在入口文件main.js中import引入即可&#xff1b;* 给elementUI的dialog上加上 v-dialogDrag 指令就可以实现弹窗的全屏和拉伸了。* 给…...

Linux 中复制文件并保持修改时间等属性

一、遇到的问题 Linux使用cp命令复制文件备份时&#xff0c;发现文件的修改时间变成当前时间了&#xff0c;想要保留备份文件原有的修改时间及其它文件属性。 二、实现 1、cp命令 在 Linux 中&#xff0c;你可以使用 cp 命令来复制文件&#xff0c;并通过 -p 或 --preserve…...

Hugging News #0814: Llama 2 学习资源大汇总

每一周&#xff0c;我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新&#xff0c;包括我们的产品和平台更新、社区活动、学习资源和内容更新、开源库和模型更新等&#xff0c;我们将其称之为「Hugging News」。本期 Hugging News 有哪些有趣的消息&#xff0…...

​可视化绘图技巧100篇进阶篇(五)-阶梯线图(Step Chart)

目录 前言 图表类型特征 适用场景 图例 绘图工具及代码实现 ECharts SMARTBI...

GPT带我学-设计模式-命令模式

1 你知道设计模式的命令模式吗 是的&#xff0c;我知道设计模式中的命令模式。命令模式是一种行为型设计模式&#xff0c;它将请求封装成一个对象&#xff0c;从而允许使用不同的请求、队列或日志来参数化其他对象。命令模式还支持撤销操作&#xff0c;并且可以提供事务的实现…...

互联网发展历程:跨越远方,路由器的启示

互联网的蓬勃发展&#xff0c;一直在追求更广阔的连接&#xff0c;更遥远的距离。然而&#xff0c;在早期的网络中&#xff0c;人们面临着连接距离有限的问题。一项重要的技术应运而生&#xff0c;那就是“路由器”。 连接受限的问题&#xff1a;距离有限 早期的网络受限于直接…...

postman入门基础 —— 接口测试流程

一、编写接口测试计划 接口测试计划和功能测试计划目标一致&#xff0c;都是为了确认需求、确定测试环境、确定测试方法&#xff0c;为设计测试用例做准备&#xff0c;初步制定接口测试进度方案。一般来说&#xff0c;接口测试计划包括概述、测试资源、测试功能、测试重点、测试…...

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…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

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音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...