共享内存喜欢沙县小吃
旭日新摊子好耶!
系统从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主对保持时间和建立时间的解读,是从另一个角度,…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
