共享内存喜欢沙县小吃
旭日新摊子好耶!
系统从0开始搭建过通信方案,本地通信方案的代码:System V IPC
里面有共享内存、消息队列、信号量
共享内存
原理
两个进程有自己的内存区域划分,共享内存被创建出的时候是归属操作系统的,还是通过页表来映射以使用物理内存
而用地址空间进行映射让两个进程看到同一份物理内存的方式叫共享内存
所有的操作都是操作系统完成的,但是它并不知道什么时候做(决定通信的是进程)

所以OS必须提供系统调用供进程进行调用,共享内存在系统中可以同时存在多份,供不同个数,不同对进程同时进行通信,共享内存不是简单的一段内存空间,也要有描述并管理共享内存的数据结构和匹配的算法
对共享内存的管理最后要变成对链表的增删查改,共享内存 = 内存空间数据 + 内存属性
代码
怎样创建共享内存呢?
需要看一个函数捏:

第二个参数代表共享内存的大小,第三个参数代表标记位
它本质采取位图的方式传参
标志位:
IPC_CREAT:如果要创建的共享内存不存在,就创建,若存在就获取该共享内存并返回(总能获取一个)
IPC_EXCL:单独使用无意义
IPC_CREAT | IPC_EXCL:如果要创建的共享内存不存在,创建,存在则出错并返回(成功返回的一定是全新的)
有个问题:进程如何知道操作系统是否存在捏?
肯定有标识共享内存唯一性的字段,进程通过唯一性标识符发现
如果让OS自动生成这个标识符是否可行?
不行耶,进程母鸡啊
key由用户形成,只要有唯一性即可
key是用来标识共享内存唯一性的字段,是由用户设计的,有统一标准,就能一个创建,一个获取
由于我们也不知道该设定多少,所以系统为我们提供了一个随机生成key的函数:ftok

于是可以这样设计:
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>const std::string pathname = "/root/ice/pineapple/shm";
const int proj_id = 0x49;key_t GetCommKey(const std::string &pathname,int proj_id)
{key_t k = ftok(pathname.c_str(),proj_id);if(k < 0){perror("ftok");}return k;
}#endif
我们,微笑的弧度一样了!
shmget的返回值是共享内存的标识符
共享内存不随着进程的结束而释放(一直存在,直到系统重启)
要手动释放,指令或者其他系统调用
文件的生命周期随进程,而共享内存的生命周期随内核
可以这样查共享内存:
ipcs -m

想要删除这个共享内存:
ipcrm -m shmid
那key和shmid有何区别呢?
key是用户形成,内核使用的一个字段,用户不能用key进行shm的管理,是内核进行区分shm唯一性的
而shmid是内核返回给用户的一个标识符,是用来进行用户级对共享内存进行管理的id值
对上面的代码进行封装:
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;class Shm
{
private:
key_t GetCommKey()
{key_t k = ftok(_pathname.c_str(),_proj_id);if(k < 0){perror("ftok");}return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{int shmid = shmget(key,size,flag);if(shmid < 0){perror("shmget");}return shmid;
}
public:Shm(const std::string &pathname, int proj_id,int who):_pathname(pathname),_proj_id(proj_id),_who(who){_key = GetCommKey();if(_who == gCreater) GetShmUserCreate();else if(_who == gUser) GetShmForUse();}~Shm();//转十六进制捏
std::string ToHex()
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",_key);return buffer;
}
bool GetShmUserCreate()
{if(_who == gCreater){_shmid = ShmGet(_key,gShmSize,IPC_CREAT | IPC_EXCL);if(_shmid >= 0){return true;}}return false;
}
bool GetShmForUse()
{if(_who == gUser){_shmid = ShmGet(_key,gShmSize,IPC_CREAT);if(_shmid >= 0){return true;}}return false;
}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;
};
删除共享内存老是用指令删太挫了,,,看我这招!

了解一下这个:

一个命令,标志共享内存删除
加上析构:
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>
#include<unistd.h>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;class Shm
{
private:
key_t GetCommKey()
{key_t k = ftok(_pathname.c_str(),_proj_id);if(k < 0){perror("ftok");}return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{int shmid = shmget(key,size,flag);if(shmid < 0){perror("shmget");}return shmid;
}
public:Shm(const std::string &pathname, int proj_id,int who):_pathname(pathname),_proj_id(proj_id),_who(who){_key = GetCommKey();if(_who == gCreater) GetShmUserCreate();else if(_who == gUser) GetShmForUse();}~Shm(){if(_who == gCreater){int res = shmctl(_shmid,IPC_RMID,nullptr);}std::cout << "shm remove done ..." << std::endl;}//转十六进制捏
std::string ToHex()
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",_key);return buffer;
}
bool GetShmUserCreate()
{if(_who == gCreater){_shmid = ShmGet(_key,gShmSize,IPC_CREAT | IPC_EXCL);if(_shmid >= 0){return true;}}return false;
}
bool GetShmForUse()
{if(_who == gUser){_shmid = ShmGet(_key,gShmSize,IPC_CREAT);if(_shmid >= 0){return true;}}return false;
}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;
};
#endif
要完成剩下的操作,需要挂接一下:

共享内存滞销,shmat帮帮我们
shmat是将共享内存挂接到地址空间中,shmdt是取消挂接
void *shmat(int shmid,const void *shmaddr,int shmflg);
第一个参数是我们申请的共享内存,第二个参数是我们想挂接到哪个地址上,第三个参数指共享内存的访问权限
先写下代码:
Shm.hpp:
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>
#include<unistd.h>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;class Shm
{
private:
key_t GetCommKey()
{key_t k = ftok(_pathname.c_str(),_proj_id);if(k < 0){perror("ftok");}return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{int shmid = shmget(key,size,flag);if(shmid < 0){perror("shmget");}return shmid;
}
std::string RoleToString(int who)
{if(who == gCreater){return "Creater";}else if(who == gUser){return "User";}else{return "None";}
}
public:Shm(const std::string &pathname, int proj_id,int who):_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr){_key = GetCommKey();if(_who == gCreater) GetShmUserCreate();else if(_who == gUser) GetShmForUse();_addrshm = AttachShm();}~Shm(){if(_who == gCreater){int res = shmctl(_shmid,IPC_RMID,nullptr);}std::cout << "shm remove done ..." << std::endl;}//转十六进制捏
std::string ToHex()
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",_key);return buffer;
}
bool GetShmUserCreate()
{if(_who == gCreater){_shmid = ShmGet(_key,gShmSize,IPC_CREAT | 0666); //不用IPC_EXCL,避免在已经存在的时候出错if(_shmid >= 0){return true;}std::cout << "shm create done..." << std::endl;}return false;
}
bool GetShmForUse()
{if(_who == gUser){_shmid = ShmGet(_key,gShmSize,IPC_CREAT);if(_shmid >= 0){return true;}}return false;
}
void *AttachShm()
{if(_addrshm != nullptr){DetachShm(_addrshm);}void *shmaddr = shmat(_shmid,nullptr,0); if(shmaddr == (void*)-1){perror("shmat");}std::cout << "AttachShm " << RoleToString(_who) << std::endl;return shmaddr;
}void DetachShm(void *shmaddr)
{if(shmaddr == nullptr){return;}shmdt(shmaddr);std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}
void *Addr()
{return _addrshm;
}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;void *_addrshm;
};#endif
server.cc:
#include"Shm.hpp"int main()
{//又是一天,什么都没有改变Shm shm(gpathname,gproj_id,gCreater);char* shmaddr = (char*)shm.Addr(); while (true){std::cout << "shm memory content: " << shmaddr <<std::endl;sleep(1);}return 0;
}
client.cc:
#include"Shm.hpp"int main()
{Shm shm(gpathname,gproj_id,gUser);char* shmaddr = (char*)shm.Addr(); char ch = 'A';while (ch <= 'Z'){shmaddr[ch - 'A'] = ch;ch++;sleep(1);}return 0;
}
while :; do ipcs -m;sleep 1;done

perm表示共享内存的权限,所以我们在创建的时候应该指定一下权限
截止目前,我们是否开始通信了呢?
没有啊
我们还没通信过,之前干的都是准备工作啊亲
eeeee哈哈哈哈哈哈
呜呜呜呜
啦啦啦啦啦啦啦啦
我碎掉咯
给自己提个醒,写错过的地方:

我们需要让挂接前共享内存先清空,所以添加个接口(Shm.hpp里面Shm的成员函数)Zero:
void Zero()
{if(_addrshm){memset(_addrshm,0,gShmSize);}
}
#include"Shm.hpp"int main()
{Shm shm(gpathname,gproj_id,gUser);shm.Zero();char* shmaddr = (char*)shm.Addr(); char ch = 'A';while (ch <= 'Z'){shmaddr[ch - 'A'] = ch;ch++;sleep(1);}return 0;
}
我现在遇到了一个问题,我刚发现我设置权限为0666了,但是共享内存的权限依旧是0,但这不是最离谱的,最离谱的是我的服务端和我的客户端都可以正常挂接上

本着遇到困难睡大觉的原则,我问了chat好几遍,调试信息也多次显示创建出的权限就是0,我真的不知道我哪里错了,所以决定在这里粘个源代码供后人嘲笑(相当于权限都是0,但是所有人可读可写可访问):
Shm.hpp:
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<string>
#include<unistd.h>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;class Shm
{
private:
key_t GetCommKey()
{key_t k = ftok(_pathname.c_str(),_proj_id);if(k < 0){perror("ftok");}return k;
}
//创建共享内存
// int ShmGet(key_t key,int size,int flag)
// {
// int shmid = shmget(key,size,flag);
// if(shmid < 0)
// {
// perror("shmget");
// }
// return shmid;
// }
std::string RoleToString(int who)
{if(who == gCreater){return "Creater";}else if(who == gUser){return "User";}else{return "None";}
}
public:Shm(const std::string &pathname, int proj_id,int who):_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr){_key = GetCommKey();if(_who == gCreater) GetShmUserCreate();else if(_who == gUser) GetShmForUse();_addrshm = AttachShm();}~Shm(){if(_who == gCreater){int res = shmctl(_shmid,IPC_RMID,nullptr);}std::cout << "shm remove done ..." << std::endl;}//转十六进制捏
std::string ToHex()
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",_key);return buffer;
}
bool GetShmUserCreate()
{if(_who == gCreater){_shmid = shmget(_key,gShmSize,IPC_CREAT | 0666); //不用IPC_EXCL,避免在已经存在的时候出错//调试代码,我看看权限是什么,会不会是显示的问题struct shmid_ds shm_info;if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) {perror("shmctl IPC_STAT");} else {std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;}if(_shmid >= 0){return true;}std::cout << "shm create done..." << std::endl;}return false;
}
bool GetShmForUse()
{if(_who == gUser){_shmid = shmget(_key,gShmSize,IPC_CREAT | 0666); //哈哈,真是令人忍俊不禁struct shmid_ds shm_info;//调试代码,我看看权限是什么,会不会是显示的问题if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) {perror("shmctl IPC_STAT");} else {std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;}if(_shmid >= 0){return true;}}return false;
}// // 更改共享内存权限,我先注释掉
// void SetShmPermissions(int shmid, mode_t perms)
// {
// struct shmid_ds shm_info;
// if (shmctl(shmid, IPC_STAT, &shm_info) == -1)
// {
// perror("shmctl IPC_STAT");
// return;
// }// shm_info.shm_perm.mode = perms;
// if (shmctl(shmid, IPC_SET, &shm_info) == -1)
// {
// perror("shmctl IPC_SET");
// }
// }void *AttachShm()
{if(_addrshm != nullptr){DetachShm(_addrshm);}void *shmaddr = shmat(_shmid,nullptr,0); if(shmaddr == (void*)-1){perror("shmat");}std::cout << "AttachShm " << RoleToString(_who) << std::endl;return shmaddr;
}void DetachShm(void *shmaddr)
{if(shmaddr == nullptr){return;}shmdt(shmaddr);std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}void Zero()
{if(_addrshm){memset(_addrshm,0,gShmSize);}
}void *Addr()
{return _addrshm;
}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;void *_addrshm;
};#endif
Server.cc:
#include"Shm.hpp"int main()
{//又是一天,什么都没有改变Shm shm(gpathname,gproj_id,gCreater);char* shmaddr = (char*)shm.Addr(); while (true){std::cout << "shm memory content: " << shmaddr <<std::endl;sleep(1);}return 0;
}
Client.cc:
#include"Shm.hpp"int main()
{Shm shm(gpathname,gproj_id,gUser);char* shmaddr = (char*)shm.Addr(); char ch = 'A';while (ch <= 'Z'){shmaddr[ch - 'A'] = ch;ch++;sleep(1);}return 0;
}
这是一些报错信息:



《这确实是不寻常的》


要爱自己,不要为难自己
共享内存不提供对共享内存的任意保护机制,会造成数据不一致的问题
这是缺点
我们在访问共享内存的时候,没有使用系统调用
共享内存是所有进程IPC速度最快的,因为共享内存大大的减少了数据的拷贝次数
我们可以基于管道对双方进行保护:
namedPiped.hpp
#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>
#include<fcntl.h>#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096const std::string comm_path = "./myfifo";class NamePiped
{
private://打开文件的模式bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(),mode);if(_fd < 0){return 0;}return true;}
public:NamePiped(const std::string &path,int who):_fifo_path(path), _id(who),_fd(DefaultFd){if(_id == Creater){int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}//输出:const &:const std::string &XXX//输入:* std::string *//输入输出:& std::string &int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd,buffer,sizeof(buffer));if(n > 0){//读取成功buffer[n] = 0;*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd,in.c_str(),in.size());}~NamePiped(){if(_id == Creater){int res = unlink(_fifo_path.c_str());if(res != 0){perror("unlink");}}if(_fd != DefaultFd){close(_fd);}}
private:const std::string _fifo_path;int _id;int _fd;
};
Shm.hpp
#define __SHM_HPP__
#ifdef __SHM_HPP__#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<string>
#include<unistd.h>const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;class Shm
{
private:
key_t GetCommKey()
{key_t k = ftok(_pathname.c_str(),_proj_id);if(k < 0){perror("ftok");}return k;
}
//创建共享内存
// int ShmGet(key_t key,int size,int flag)
// {
// int shmid = shmget(key,size,flag);
// if(shmid < 0)
// {
// perror("shmget");
// }
// return shmid;
// }
std::string RoleToString(int who)
{if(who == gCreater){return "Creater";}else if(who == gUser){return "User";}else{return "None";}
}
public:Shm(const std::string &pathname, int proj_id,int who):_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr){_key = GetCommKey();if(_who == gCreater) GetShmUserCreate();else if(_who == gUser) GetShmForUse();_addrshm = AttachShm();}~Shm(){if(_who == gCreater){int res = shmctl(_shmid,IPC_RMID,nullptr);}std::cout << "shm remove done ..." << std::endl;}//转十六进制捏
std::string ToHex()
{char buffer[128];snprintf(buffer,sizeof(buffer),"0x%x",_key);return buffer;
}
bool GetShmUserCreate()
{if(_who == gCreater){_shmid = shmget(_key,gShmSize,IPC_CREAT | 0666); //不用IPC_EXCL,避免在已经存在的时候出错//调试代码,我看看权限是什么,会不会是显示的问题struct shmid_ds shm_info;if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) {perror("shmctl IPC_STAT");} else {std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;}if(_shmid >= 0){return true;}std::cout << "shm create done..." << std::endl;}return false;
}
bool GetShmForUse()
{if(_who == gUser){_shmid = shmget(_key,gShmSize,IPC_CREAT | 0666); //哈哈,真是令人忍俊不禁struct shmid_ds shm_info;//调试代码,我看看权限是什么,会不会是显示的问题if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) {perror("shmctl IPC_STAT");} else {std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;}if(_shmid >= 0){return true;}}return false;
}// // 更改共享内存权限,我先注释掉
// void SetShmPermissions(int shmid, mode_t perms)
// {
// struct shmid_ds shm_info;
// if (shmctl(shmid, IPC_STAT, &shm_info) == -1)
// {
// perror("shmctl IPC_STAT");
// return;
// }// shm_info.shm_perm.mode = perms;
// if (shmctl(shmid, IPC_SET, &shm_info) == -1)
// {
// perror("shmctl IPC_SET");
// }
// }void *AttachShm()
{if(_addrshm != nullptr){DetachShm(_addrshm);}void *shmaddr = shmat(_shmid,nullptr,0); if(shmaddr == (void*)-1){perror("shmat");}std::cout << "AttachShm " << RoleToString(_who) << std::endl;return shmaddr;
}void DetachShm(void *shmaddr)
{if(shmaddr == nullptr){return;}shmdt(shmaddr);std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}void Zero()
{if(_addrshm){memset(_addrshm,0,gShmSize);}
}void *Addr()
{return _addrshm;
}private:key_t _key;int _shmid;std::string _pathname;int _proj_id;int _who;void *_addrshm;
};#endif
client.cc
#include"Shm.hpp"
#include"namedPiped.hpp"int main()
{//创建共享内存Shm shm(gpathname,gproj_id,gUser);char* shmaddr = (char*)shm.Addr(); //打开管道NamePiped fifo(comm_path,User);fifo.OpenForWrite();char ch = 'A';while (ch <= 'Z'){shmaddr[ch - 'A'] = ch;ch++;std::string temp = "wakeup";std::cout << "add" << ch << "into Shm, " << "wakeup reader" << std::endl;fifo.WriteNamedPipe(temp);sleep(1);}return 0;
}
server.cc
#include"Shm.hpp"
#include"namedPiped.hpp"int main()
{//又是一天,什么都没有改变//创建共享内存Shm shm(gpathname,gproj_id,gCreater);char* shmaddr = (char*)shm.Addr(); //创建管道NamePiped fifo(comm_path,Creater);fifo.OpenForRead();while (true){std::string temp;fifo.ReadNamedPipe(&temp);std::cout << "shm memory content: " << shmaddr <<std::endl;sleep(1);}return 0;
}
共享内存的设置最好设置成4096的整数倍,如果多一点点会浪费
因为操作系统只会给你分配4096的整数倍的共享内存
怎样获取共享内存的属性捏?

void DebugShm()
{struct shmid_ds ds;int n = shmctl(_shmid,IPC_STAT,&ds);if(n < 0){return;}std::cout << "ds.shm_perm.__key: " << ToHex(ds.shm_perm.__key) << std::endl;std::cout << "ds.shm_nattch: " << ds.shm_nattch << std::endl;
}

System V消息队列
原理
操作系统申请个队列,现在有两个进程:进程A+进程B,进程A可以使用消息队列的调用接口,向消息队列中放数据块,消息队列是一个进程向另一个进程发送数据块的方式,操作系统也要先描述在组织,所以不仅要有消息队列,还要有相应的属性数据
接口
那有哪些接口呢,让我们康康
int msgget(key_t key,int msgflg);

这个接口是在获取消息队列
key_t fork(const char *pathname,int proj_id);

消息队列使用的时候和共享内存差不多,不想用了的话就可以用msgctl捏
int msgctl(int msqid,int cmd,struct msqid_ds *buf);

我们消息队列也有自己的属性捏

消息队列是收发结点,共享内存是挂接
发消息捏:
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);

使用消息队列需要我们自定义一个结构体,msgbuf
struct msgbuf
{long mtype; /*message type,must be > 0 */char mtext[1]; /*message data */
};
这个大小是自己定义的捏
发消息是这样的捏:
#define A 1
#define B 2
struct msgbuf message;
message.mtype = B;
message.mtext = ("hello world");
msgsnd(msgid,&message,sizeof(message),0);
收消息则可以这样干:
#define A 1
#define B 2
struct msgbuf recvbuffer;
msgrcv(msgid,&recvbuffer,sizeof(recvbuffer),A,0);
msgrcv(msgid,&recvbuffer,sizeof(recvbuffer),B,0);
指令操作
生命周期是随内核的鹅,可以这样查看消息队列:
ipcs -q

删除的话就是:
ipcrm -q msqid

距离永远不会成为阻碍

毛豆好可爱







很好笑,下了拜拜
相关文章:
共享内存喜欢沙县小吃
旭日新摊子好耶! 系统从0开始搭建过通信方案,本地通信方案的代码:System V IPC 里面有共享内存、消息队列、信号量 共享内存 原理 两个进程有自己的内存区域划分,共享内存被创建出的时候是归属操作系统的,还是通过…...
五、Build构建配置:jar包换名、自行定义编译规则
(1)jar包换名:finalName (2)自行定义编译规则(通常不用) Maven约定的规则就是java目录下写java代码,resources目录下写配置文件。 遵循规则,Maven会帮忙做编译。 如若…...
Html、Css3动画效果
文章目录 第九章 动画9.1 transform动画9.2 transition过渡动画9.3 定义动画 第九章 动画 9.1 transform动画 transform 2D变形 translate():平移函数,基于X、Y坐标重新定位元素的位置 scale():缩放函数,可以使任意元素对象尺…...
【AIStarter:AI绘画、设计、对话】零基础入门:Llama 3.1 + 千问2快速部署
对于希望在本地环境中运行先进语言模型的用户来说,Llama 3.1和千问2是非常不错的选择。本文将详细介绍如何在本地部署这两个模型,让你能够快速开始使用。 前期准备 确保你的计算机具备足够的存储空间和计算能力。安装Python环境以及必要的库࿰…...
多机编队—(1)ubuntu 配置Fast_Planner
文章目录 前言一、Could not find package ...二、使用error: no match for ‘operator’...总结 前言 最近想要做有轨迹引导的多机器人编队,打算采用分布式的编队架构,实时的给每个机器人规划出目标位置,然后通过Fast_Planner生成避障路径&…...
【数学建模经验贴】国赛拿到赛题后,该如何选题?
2024“高教社杯”全国大学生数学建模竞赛即将开赛。这可能是很多同学第一次参加国赛,甚至是第一次参加数学建模比赛。 那么赛题的公布也就意味着比赛的开始,也将是我们所要面对的第一个问题——选题。在国赛来临的前夕,C君想和大家聊一聊容易…...
如何快速融入大学课堂
快速融入大学课堂是适应大学生活的重要一步。以下是一些实用的建议,帮助你快速融入大学课堂并取得良好的学习效果。 ### 1. 提前准备 - **课前预习**:在上课前预习课程内容,了解基本概念和知识点,这样在课堂上更容易跟上老师的讲…...
el-table行编辑
需求:单点行编辑并且请求接口更新数据,表格中某几个字段是下拉框取值的,剩下的是文本域;展示的时候 需要区分下拉框编码还是中文 故障模式这个展示的是fault_mode编码,但要显示的文字fault_mode_chn 这点需要注意 <el-tablere…...
OpenSSL Windows编译
目录 1. 源码下载2. vs2022编译 1. 源码下载 源码地址 2. vs2022编译 (1) 将“VS2022安装目录VC\Auxiliary\Build\“设置为PATH环境变量,启动cmd命令行(一定要先设置环境变量)。 (2)在cmd下进入VS2013安装目录vs2022\VC\Auxiliary\Build&…...
优化LabVIEW中TCP通信速度的方法
在LabVIEW中,TCP通信速度较慢可能由多种因素导致,如数据包处理延迟、阻塞式读取或数据解析效率低等。通过调整读取模式、优化数据处理逻辑、以及使用并行处理结构,可以显著提升TCP通信的速度,使其接近第三方调试工具的表现。LabVI…...
【视频讲解】Python贝叶斯卷积神经网络分类胸部X光图像数据集实例
全文链接:https://tecdat.cn/?p37604 分析师:Yuanchun Niu 在人工智能的诸多领域中,分类技术扮演着核心角色,其应用广泛而深远。无论是在金融风险评估、医疗诊断、安全监控还是日常的交互式服务中,有效的分类算法都是…...
src/pyaudio/device_api.c:9:10: fatal error: portaudio.h: 没有那个文件或目录
(venv) shgbitaishgbitai-C9X299-PGF:~/pythonworkspace/ai-accompany$ pip install pyaudio sounddevice Collecting pyaudioDownloading PyAudio-0.2.14.tar.gz (47 kB)━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 47.1/47.1 kB 644.…...
移动端视频编辑SDK解决方案,AI语音识别添加字幕
对于众多Vlog创作者而言,繁琐的字幕添加过程往往成为提升内容质量的绊脚石。为了彻底改变这一现状,美摄科技凭借其深厚的AI技术积累与创新的移动端视频编辑SDK解决方案,推出了革命性的AI语音识别添加字幕功能,让视频创作更加高效、…...
WIN11 ESP32 IDF + VSCODE 环境搭建[教程向]
前言 目录 前言 安装ESP32-IDF VSCODE插件安装 编译测试 很多时候我们想学习一门新的技能,需要使用全新的开发环境,很多时候我们会在安装环境这个环节卡住很久,这里简单介绍一下ESP32VSCODE环境搭建。 安装ESP32-IDF https://dl.espre…...
Gemini AI 与 ChatGPT:哪个更适合为我策划婚礼?
我在六月订婚后,一心想着婚礼钟声,但在看到这些婚礼场地报价后,更像是警铃声响起。 “叮咚”已经被重新混音成“哗啦啦”——我需要帮助。 我甚至不知道如何 开始 计划婚礼。第一步是什么?我需要优先考虑什么?哪些任…...
log4j 同一线程隔离classloader下MDC信息不同问题解决 ThreadLocal问题分析
最近遇到日志文件记录错误的问题。一个任务的日志信息会被莫名的拆分到两个不同目录中。且有一个目录还是曾经执行过的任务的目录。经过分析,首先怀疑的是MDC没有清理的问题,这也是最直观的问题。因为任务是在线程池(fixedThreadPool)中运行的。由于线程…...
【2024-2025源码+文档+调试讲解】微信小程序的城市公交查询系统
摘 要 当今社会已经步入了科学技术进步和经济社会快速发展的新时期,国际信息和学术交流也不断加强,计算机技术对经济社会发展和人民生活改善的影响也日益突出,人类的生存和思考方式也产生了变化。传统城市公交查询管理采取了人工的管理方法…...
Android14音频进阶之定制ramdisk文件系统init服务(八十三)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…...
Clickhouse 为什么这么快
Clickhouse 的缘起 Clickhouse 最初是为 Yandex.Metrica 这个世界上第二大的Web分析平台开发的,并且一直是这个系统的核心组件。ClickHouse在Yandex.Metrica中的主要任务是使用非聚合数据在在线模式下构建报告,使用374台服务器组成的集群,在…...
后仿真中《建立违例和保持违例》你死板思维了吗?
最近胡乱翻翻一些大佬的博客文章,忽然看到了关于clock skew 的一篇文章,文章的链接贴在这里,供大家查阅。《Clock skew (qq.com)》。那么,这篇文章与今天的主题,由什么关系呢? 是因为,从中看到了关于时序违例的解读。UP主对保持时间和建立时间的解读,是从另一个角度,…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
