IO进程线程(十)进程间通信 消息队列 共享内存 信号灯集

文章目录

  • 一、IPC(Inter-Process Communication)进程间通信相关命令 :
    • (一)ipcs --- 查看IPC对象
    • (二)获取IPC键值
    • (三)删除IPC对象的命令
    • (四)获取IPC键值的函数
      • 1. 函数定义
      • 2. 使用示例
  • 二、消息队列
    • (一) 特点
    • (二) 相关API
      • 1. 创建或获取一个消息队列
      • 2. 向消息队列中写消息
      • 3. 在消息队列中读取一条消息
      • 4. 控制消息队列
    • (三) 不关注消息类型
    • (四)关注消息类型
    • (五)消息队列属性结构体
  • 三、共享内存 shared memory(shm)
    • (一)特点
    • (二) 相关API
      • 1. 创建共享内存
      • 2. 映射共享内存到当前的进程空间
      • 3. 取消地址映射
      • 4. 共享内存控制
    • (三)使用示例
    • (四) 属性
  • 四、信号灯集---控制进程间同步
    • (一)特点
    • (二) 相关API
    • (三) 原生函数使用示例
    • (四)封装函数

一、IPC(Inter-Process Communication)进程间通信相关命令 :

(一)ipcs — 查看IPC对象

在这里插入图片描述

(二)获取IPC键值

ipcs -q 查看消息队列
在这里插入图片描述

ipcs -m 查看共享内存
在这里插入图片描述

ipcs -s 查看信号灯集
在这里插入图片描述

(三)删除IPC对象的命令

ipcrm -q id 删除消息队列
ipcrm -m id 删除共享内存
ipcrm -s id 删除信号灯集

(四)获取IPC键值的函数

1. 函数定义

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:使用给定的文件和字符来生成一个IPC通信的key值
参数:pathname:路径和文件名(必须是已存在的可访问的)proj_id:[0-255]的值  一般我们传一个字符即可 如 'A'  'm'
返回值:成功  key值失败  -1  重置错误码
  • 注:
  • typedef int key_t key_t 即 int 类型
  • pathname 要求必须是一个已存在的文件,因为key值的是由proj_id的后八位,设备号的后8位以及inode号的后16位组成。因此这种机制并不保证key值一定不重复
  • proj_id 只是用了int的一个字节,即取值范围是[0-255],一般使用时传一个字符,字符ASCII码是0-127。

2. 使用示例

生成并打印出key,分析key值的由来

验证代码

#include <my_head.h>int main(int argc, char const *argv[])
{key_t key=0;key = ftok("/home/linux/05work",'A');printf("my_key = %#x\n",key);struct stat file_stat= {0};stat("/home/linux/05work",&file_stat);printf("proj_id=%#x  dev=%#lx inode=%#lx\n",'A', file_stat.st_dev, file_stat.st_ino);return 0;
}

输出结果
在这里插入图片描述

二、消息队列

(一) 特点

  1. 消息队列也是基于内核实现的,存放在内存上(而非硬盘上)。
  2. 消息队列的大小,默认是 16K。
  3. 消息队列中的消息有类型和正文。
    A进程将消息写入消息队列;
    B进程可以根据消息的类型从消息队列中将对应类型的消息取走。
  4. 半双工通信

(二) 相关API

1. 创建或获取一个消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgget(key_t key, int msgflg);
功能:创建或者获取一个消息队列
参数:key:键值key 通过ftok获取的IPC_PRIVATE 表示只有亲缘进程间能用msgflg:消息队列的标志位IPC_CREAT|0666 消息队列不存在则创建,权限0666 或者  IPC_CREAT|IPC_EXCL|0666 消息不存在则创建,存在则但会-1,置错误码为EEXIST
返回值:成功 消息队列的id失败 -1 重置错误码

2. 向消息队列中写消息

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列中写入一条消息
参数:msqid:消息队列的idmsgp: 要写入的数据的首地址struct msgbuf {long mtype;      /* 消息的类型 必须大于 0 */char mtext[1];   /* 消息正文 可以自定义 */};msgsz:消息正文的大小msgflg:标志位 0 阻塞发送  IPC_NOWAIT 非阻塞发送
返回值:成功 0失败 -1  重置错误码
  • 注:
  • 关于void *msgp参数,第一个long类型大小的空间必须用来存放消息的类型,消息的正文可以自定义
  • size_t msgsz参数,只包含正文数据的大小(sizeof(struct msgbuf)-sizeof(mtype))
  • 阻塞发送的情况下,如果消息队列满了,A进程还想向消息队列中写入消息,此时A进程将会阻塞。

3. 在消息队列中读取一条消息

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
功能:在消息队列中读取一条消息
参数:msqid:消息队列的idmsgp: 用来保存接收的数据的缓冲区的首地址struct msgbuf {long mtype;     /* 消息的类型 必须大于 0 */char mtext[1];  /* 消息正文 可以自定义 */};msgsz:消息正文的大小msgtyp:要接受的消息的类型0 :接收消息队列中第一条消息>0 : 接收指定类型的第一条消息<0 :一般不使用,了解即可,表示接收消息队列中第一条类型最小的小于msgtyp的绝对值的消息3-2-5-500-200-8读取时,类型传 -200读取的顺序  2-3-5 msgflg:标志位 0 阻塞接收  IPC_NOWAIT 非阻塞接收
返回值:成功 实际读到的正文的字节数失败 -1  重置错误码
  • 注:读消息队列和写消息队列中的void *msgp结构体的内部成员要尽量对应。

4. 控制消息队列

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列
参数:msqid:消息队列idcmd:指令IPC_STAT:获取消息队列的属性IPC_SET:设置消息队列的属性IPC_RMID:立即删除消息队列只有消息队列的创建者和所有者以及root用户可以删除消息队列msgctl函数的第三个参数被忽略buff:属性结构体的地址
返回值:成功 0失败 -1  重置错误码

(三) 不关注消息类型

此时进程间通信不关心消息类型,按顺序接收第一条消息。
注意,当其中一个进程关闭消息队列后,另一个进程再试图关闭,就会报错,错误码EINVAL

read.c

#include <my_head.h>typedef struct msgbuf{long type;char name[20];
}msg_t;int main(int argc, char const *argv[])
{//获取key值key_t key=ftok("/home/linux/05work",'A');//创建消息队列int msgid = msgget(key,IPC_CREAT|0666);if(-1 == msgid)ERR_LOG("msgget error");//定义消息结构体msg_t msg={0};int type=0;while(1){if(-1 == msgrcv(msgid,&msg,sizeof(msg_t)-sizeof(msg.type),type,0)){ERR_LOG("msgrcv error");}if(!strcmp(msg.name,"quit")){break;}printf("%ld:%s\n",msg.type,msg.name);}if(-1 == msgctl(msgid,IPC_RMID,NULL)){if(EINVAL == errno){return 0;}ERR_LOG("msgctl error");}return 0;
}

write.c

#include <my_head.h>typedef struct msgbuf{long type;char name[20];
}msg_t;int main(int argc, char const *argv[])
{//获取key值key_t key=ftok("/home/linux/05work",'A');//创建消息队列int msgid = msgget(key,IPC_CREAT|0666);if(-1 == msgid)ERR_LOG("msgget error");//定义消息结构体msg_t msg={0};while(1){printf("请输入消息:<类型> <正文>:");scanf("%ld %s",&msg.type,msg.name);msgsnd(msgid,&msg,sizeof(msg_t)-sizeof(msg.type),0);if(!strcmp(msg.name,"quit")){break;}}//销毁消息队列if(-1 == msgctl(msgid,IPC_RMID,NULL)){if(EINVAL == errno){return 0;}ERR_LOG("msgctl error");}return 0;
}

(四)关注消息类型

此时进程间通信关心消息类型,按顺序接收第一条符合类型的消息,如果消息队列中没有同类型消息,会阻塞等待。
在这里插入图片描述
read.c

#include <my_head.h>typedef struct msgbuf{long type;char name[20];
}msg_t;int main(int argc, char const *argv[])
{//获取key值key_t key=ftok("/home/linux/05work",'A');//创建消息队列int msgid = msgget(key,IPC_CREAT|0666);if(-1 == msgid)ERR_LOG("msgget error");//定义消息结构体msg_t msg={0};int type=0;while(1){printf("请输入想要接收的消息类型:");scanf("%d",&type);if(-1 == msgrcv(msgid,&msg,sizeof(msg_t)-sizeof(msg.type),type,0)){ERR_LOG("msgrcv error");}if(!strcmp(msg.name,"quit")){break;}printf("%ld:%s\n",msg.type,msg.name);}if(-1 == msgctl(msgid,IPC_RMID,NULL)){if(EINVAL == errno){return 0;}ERR_LOG("msgctl error");}return 0;
}

write.c

#include <my_head.h>typedef struct msgbuf{long type;char name[20];
}msg_t;int main(int argc, char const *argv[])
{//获取key值key_t key=ftok("/home/linux/05work",'A');//创建消息队列int msgid = msgget(key,IPC_CREAT|0666);if(-1 == msgid)ERR_LOG("msgget error");//定义消息结构体msg_t msg={0};while(1){printf("请输入消息:<类型> <正文>:");scanf("%ld %s",&msg.type,msg.name);msgsnd(msgid,&msg,sizeof(msg_t)-sizeof(msg.type),0);if(!strcmp(msg.name,"quit")){break;}}//销毁消息队列if(-1 == msgctl(msgid,IPC_RMID,NULL)){if(EINVAL == errno){return 0;}ERR_LOG("msgctl error");}return 0;
}

(五)消息队列属性结构体

struct msqid_ds {struct ipc_perm msg_perm;     /* IPC权限结构体 */time_t          msg_stime;    /* 最后一次执行msgsnd的时间 */time_t          msg_rtime;    /* 最后一次执行msgrcv的时间 */time_t          msg_ctime;    /* 最后一次被修改的时间 */unsigned long   __msg_cbytes; /* 当前消息队列中的字节数 */msgqnum_t       msg_qnum;     /* 当前消息队列中的消息数 */msglen_t        msg_qbytes;   /* 允许的最大字节数 */pid_t           msg_lspid;    /* 最后一次执行msgsnd的进程的PID */pid_t           msg_lrpid;    /* 最后一次执行msgrcv的进程的PID */
};struct ipc_perm {key_t          __key;       /* 键值 */uid_t          uid;         /* 所属用户的id */gid_t          gid;         /* 所属用户的组id */uid_t          cuid;        /* 创建者的id */gid_t          cgid;        /* 创建者的组id */unsigned short mode;        /* 权限 */
};
  • 注:
    qbytes可以改小,改大的话需要sudo权限

三、共享内存 shared memory(shm)

(一)特点

在内核中创建共享内存,让进程A和进程B都能够访问到,通过这段内存进行数据的传递。
共享内存是所有进程间通信方式中效率最高的(不需要来回进行数据的拷贝)
在这里插入图片描述

(二) 相关API

1. 创建共享内存

#include <sys/ipc.h>
#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);
功能:创建共享内存
参数:key:键值key 通过ftok获取IPC_PRIVATE:只能用于亲缘进程间的通信size:共享内存的大小  PAGE_SIZE(4k)的整数倍shmflg:共享的标志位IPC_CREAT|0666 或 IPC_CREAT|IPC_EXCL|0666
返回值:成功 共享内存编号失败 -1 重置错误码
  • 注:
  • 共享内存大小必须要4k的整数倍,因为一页是4k。如果申请时不要求4
    的整数倍,分配时也是分配4k的整数倍。
  • 内核空间越界会直接段错误
  • 同一个key值可以同时用于消息队列,共享内存,信号灯集

2. 映射共享内存到当前的进程空间

#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:映射共享内存到当前的进程空间
参数:shmid:共享内存编号shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL,让系统自动分配shmflg:共享内存操作方式0    读写SHM_RDONLY    只读
返回值:成功 指向共享内存的地址失败 (void *)-1 重置错误码

3. 取消地址映射

#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:取消地址映射
参数:shmaddr:指向共享内存的指针
返回值:成功 0失败 -1 重置错误码

4. 共享内存控制

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:共享内存控制的函数
参数:shmid:共享内存编号cmd:操作的命令码IPC_STAT:获取IPC_SET:设置IPC_RMID:删除共享内存标记要销毁的段。实际上,只有在最后一个进程将其分离之后 (也就是说,关联结构shmid_ds的shm_nattch成员为零时), 段才会被销毁。调用者必须是段的所有者或创建者,或具有特权。buf参数被忽略。buf:共享内存属性结构体指针
返回值:成功 0失败 -1 重置错误码

(三)使用示例

read.c

#include <my_head.h>#define SHM_PAGE 1024*4
int main(int argc, char const *argv[])
{//获取键值key_t key = ftok("/home/linux/05work",'A');if(-1 == key)ERR_LOG("ftok error");//创建共享内存int shmid = shmget(key, SHM_PAGE,IPC_CREAT|0666);if(-1 == shmid)ERR_LOG("shmget error");//映射共享内存char *addr = (char *)shmat(shmid,NULL,SHM_RDONLY);while(1){getchar();printf("%s",addr);}return 0;
}

write.c

#include <my_head.h>#define SHM_PAGE 1024*4
int main(int argc, char const *argv[])
{//获取键值key_t key = ftok("/home/linux/05work",'A');if(-1 == key)ERR_LOG("ftok error");//创建共享内存int shmid = shmget(key, SHM_PAGE,IPC_CREAT|0666);if(-1 == shmid)ERR_LOG("shmget error");//映射共享内存char *addr = (char *)shmat(shmid,NULL,0);while(1){printf("请输入要发送的内容:");scanf("%s",addr);}return 0;
}

(四) 属性

struct shmid_ds{struct ipc_perm shm_perm;    //权限结构体size_t shm_segsz;             //共享内存大小,单位是字节 __time_t shm_atime;         //最后一次映射的时间 __pid_t shm_cpid;             //创建共享内存进程的pid __pid_t shm_lpid;             //最后一次操作共享内存进程的pid shmatt_t shm_nattch;         //共享内存映射的次数
};
struct ipc_perm{__key_t __key;                //ftok获取的key__uid_t uid;                 //用户的ID__gid_t gid;                 //组ID__uid_t cuid;                //创建共享内存的用户的ID__gid_t cgid;                //创建共享内存的组的IDunsigned short int mode;     //消息队列的权限
};

四、信号灯集—控制进程间同步

(一)特点

进程间同步的机制

(二) 相关API

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能:创建一个信号灯集
参数:key:键值IPC_PRIVATE  keynsems:信号灯集合中信号灯的个数semflag:创建的标志位IPC_CREAT|0666 或 IPC_CREAT|IPC_EXCL|0666
返回值:成功 semid失败 -1  重置错误码int semctl(int semid, int semnum, int cmd, ...);
功能:信号灯集的控制函数
参数:semid信号灯集的IDsenum:信号灯的编号 从0开始cmd:命令码SETVAL:设置信号灯的值 --->第四个参数val选项GETVAL:获取信号灯的值 --->不需要第四个参数IPC_STAT:获取信号灯集的属性--->第二参数被忽略,第四个参数buf选项IPC_SET :设置信号灯集的属性--->第二参数被忽略,第四个参数buf选项IPC_RMID:删除信号灯集 第二参数被忽略,第4个参数不用填写 @...:可变参union semun{int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */};
返回值:成功:GETVAL:成功返回信号灯的值其余的命令码成功返回0失败 -1  重置错误码int semop(int semid, struct sembuf *sops, size_t nsops);
功能:信号灯集中信号灯的操作函数
参数:semid:信号灯集的编号sops:操作方式struct sembuf{unsigned short sem_num; //信号灯的编号short sem_op; //操作方式(PV)-1:P操作,申请资源 1:V操作,释放资源short sem_flg; //操作的标志位 0:阻塞 IPC_NOWAIT:非阻塞方式操作}nsops:本次操作信号灯的个数
返回值:成功 0失败 -1  重置错误码
  • 注:
  • 初始化操作必须只能一次,如果多次可能会将其他进程的值初始化
  • 同时对多个信号灯进行操作时,可以定义一个结构体数组

(三) 原生函数使用示例

(四)封装函数

原生函数直接使用会比较繁琐,因此会做二次封装。

初始化(解决可能重复初始化的问题):


P操作


V操作


销毁


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/24270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maxkb玩转大语言模型

Maxkb玩转大语言模型 随着国外大语言模型llama3的发布&#xff0c;搭建本地个人免费“人工智能”变得越来越简单&#xff0c;今天博主分享使用Max搭建本地的个人聊天式对话及个人本地知识域的搭建。 1.安装Maxkb开源应用 github docker快速安装 docker run -d --namemaxkb -p 8…

FL Studio21.2.9中文破解版水果软件安装包附带激活码注册码

音乐制作软件&#xff0c;对很多人而言&#xff0c;是一个“高门槛”的存在。它既需要专业的音乐知识&#xff0c;也需要复杂的操作技巧。 「FL Studio 21中文版马丁版下载」&#xff0c;复制整段内容&#xff0c;打开最新版「夸克APP」即可获取链接&#xff1a; https://pan…

Dokcer 基础使用 (4) 网络管理

文章目录 Docker 网络管理需求Docker 网络架构认识Docker 常见网络类型1. bridge 网络2. host 网络3. container 网络4. none 网络5. overlay 网络 Docker 网路基础指令Docker 网络管理实操 其他相关链接 Docker 基础使用(0&#xff09;基础认识 Docker 基础使用(1&#xff09;…

git(其六)--总结

配置基础信息 //1.配置用户名和邮箱 git config --global user.name "带着引号写一个昵称" git config --global user.email "带着引号写一个邮箱"//2.建立一个git本地库 git init//3.查看本地内容 git status //可以看到那些处于待加入本地库的文件&a…

使用AutoGen框架进行多智能体协作:AI Agentic Design Patterns with AutoGen

AI Agentic Design Patterns with AutoGen 本文是学习https://www.deeplearning.ai/short-courses/ai-agentic-design-patterns-with-autogen/ 这门课的学习笔记。 What you’ll learn in this course In AI Agentic Design Patterns with AutoGen you’ll learn how to buil…

当C++的static遇上了继承

比如我们想要统计下当前类被实例化了多少次&#xff0c;我们通常会这么写 class A { public:A() { Count_; }~A() { Count_--; }int GetCount() { return Count_; }private:static int Count_; };class B { public:B() { Count_; }~B() { Count_--; }int GetCount() { return …

抢人!抢人!抢人! IT行业某岗位已经开始抢人了!

所谓抢滩鸿蒙&#xff0c;人才先行。鸿蒙系统火力全开后&#xff0c;抢人已成鸿蒙市场的主题词&#xff01; 智联招聘数据显示&#xff0c;春节后首周&#xff0c;鸿蒙相关职位数同比增长163%&#xff0c;是去年同期的2.6倍&#xff0c;2023年9-12月鸿蒙相关职位数同比增速为3…

前端开发常用的工具和软件,提高编程效率

目录 1. 文本编辑器与IDE (集成开发环境)2. 版本控制工具3. 构建工具与包管理器4. 前端框架与库5. 设计与原型工具6. 测试与调试工具7. 代码协作与项目管理8. 自动化部署与持续集成/持续部署(CI/CD)相关链接&#xff1a; 前端开发过程中使用的工具和软件种类繁多&#xff0c;可…

Python实现调用并执行Linux系统命令

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

【Node】node的Events模块(事件模块)的介绍和使用

文章目录 简言EventsPassing arguments and this to listeners 向监听器传递参数Asynchronous vs. synchronous 异步和同步Handling events only once 只一次处理事件Error events 错误事件Capture rejections of promises 捕捉拒绝承诺的情况Class: EventEmitter 事件类Event:…

聊聊二叉堆、红黑树、时间轮在定时任务中的应用

定时任务作为常用的一种调度方式&#xff0c;在各大系统得到了广泛的应用。 笔者也曾写过两篇关于定时任务框架介绍的文章&#xff1a; 《介绍一下,spring cloud下的另一种定时任务解决方案》《四叉堆在GO中的应用-定时任务timer》 之前都是以如何使用为主&#xff0c;这次从…

Vue项目安装axios报错npm error code ERESOLVE npm error ERESOLVE could not resolve解决方法

在Vue项目中安装axios时报错 解决方法&#xff1a;在npm命令后面加--legacy-peer-deps 例如&#xff1a;npm install axios --save --legacy-peer-deps 因为别的需求我把node版本重装到了最新版&#xff08;不知道是不是这个原因&#xff09;&#xff0c;后来在项目中安装axi…

在推荐四款软件卸载工具,让流氓软件无处遁形

Revo Uninstaller Revo Uninstaller是一款电脑软件、浏览器插件卸载软件&#xff0c;目前已经有了17年的历史了。可以扫描所有window用户卸载软件后的残留物&#xff0c;并及时清理&#xff0c;避免占用电脑空间。 Revo Uninstaller可以通过命令行卸载软件&#xff0c;可以快速…

前端生成海报图技术选型与问题解决

作者&#xff1a;vivo 互联网大前端团队 - Tian Yuhan 本篇文章主要聚焦海报图分享这个形式&#xff0c;探讨纯前端在H5&小程序内&#xff0c;合成海报到下载到本地、分享至社交平台整个流程中可能遇到的问题&#xff0c;以及如何解决。 一、引言 绝大多数的电商平台都会…

30、matlab现代滤波:维纳滤波/LMS算法滤波/小波变换滤波

1、信号1和信号2的维纳滤波 实现代码 N 2000; %采样点数 Fs 2000; %采样频率 t 0:1 / Fs:1 - 1 / Fs; %时间序列 Signal1 sin(2*pi*20* t) sin(2*pi*40* t) sin(2*pi*60* t); Signal2[2*ones(1,50),zeros(1,50),-1*ones(1,100),zeros(1,50),-2*ones(1,50),zeros(1,50),1…

【C语言】05.数组

一、数组的概念 本文来介绍数组&#xff0c;首先我们需要了解数组是什么&#xff1f; 数组是⼀组相同类型元素的集合。 • 数组中存放的是1个或者多个数据&#xff0c;但是数组元素个数不能为0。 • 数组中存放的多个数据&#xff0c;类型是相同的。 数组分为⼀维数组和多维数组…

Go源码--sync库(2)

简介 这边文章主要讲解 Sync.Cond和Sync.Rwmutex Sync.Cond 简介 sync.Cond 经常用来处理 多个协程等待 一个协程通知 这种场景&#xff0c; 主要 是阻塞在某一协程中 等待被另一个协程唤醒 继续执行 这个协程后续的功能。cond经常被用来协调协程对某一资源的访问 ants协程池…

Win10 Edge提示兼容性问题打不开|解决浏览器兼容性问题

Edge有时候会与某些安全软件不兼容&#xff0c;导致报错 报错代码&#xff1a;STATUS_INVALID_IMAGE_HASH 解决Edge浏览器兼容性问题方法/步骤&#xff1a; 1、按 Win R 组合键&#xff0c;打开运行&#xff0c;并输入 regedit 命令&#xff0c;确定或回车&#xff0c;可以…

SAP ERP系统主要模块简介

SAP系统通过提供一系列高度灵活的模块&#xff0c;满足企业在不同业务领域的需求。这些模块不仅功能齐全且相对独立&#xff0c;但它们之间又能紧密协作&#xff0c;共同构筑一个协同高效的工作环境。 财务会计&#xff08;FI&#xff09;模块 它涵盖了总账、应收账款、应付账…

DexCap——斯坦福李飞飞团队泡茶机器人:更好数据收集系统的原理解析、源码剖析

前言 2023年7月&#xff0c;我司组建大模型项目开发团队&#xff0c;从最开始的论文审稿&#xff0c;演变成目前的两大赋能方向 大模型应用方面&#xff0c;以微调和RAG为代表 除了论文审稿微调之外&#xff0c;目前我司内部正在逐一开发论文翻译、论文对话、论文idea提炼、论…