共享内存喜欢沙县小吃
旭日新摊子好耶!
系统从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主对保持时间和建立时间的解读,是从另一个角度,…...

springboot启动时替换配置参数
SpringBoot启动时配置参数替换 一.背景 SpringBoot项目启动的时候,在不使用配置中心等的前提下或者有公司强制使用指定的“密码箱”情况下,需要远程获取关键配置信息,比如数据库密码,则需要在项目启动前获取配置并且进行本地配置…...

postgres数据库中如何看查询是否走索引,以及在什么情况下走索引
在 PostgreSQL 中,可以通过 EXPLAIN 或 EXPLAIN ANALYZE 查看查询计划,以判断查询是否使用了索引。除此之外,了解索引的使用条件对于优化查询性能也很重要。 1. 如何查看查询是否使用索引 使用 EXPLAIN 查看查询计划 EXPLAIN 显示 PostgreSQL 如何执行查询,包括是否使用索…...

AI预测福彩3D采取888=3策略+和值012路或胆码测试9月7日新模型预测第80弹
经过近80期的测试,当然有很多彩友也一直在观察我每天发的预测结果,得到了一个非常有价值的信息,那就是9码定位的命中率非常高,70多期一共只错了8次,这给喜欢打私房菜的朋友提供了极高价值的预测结果~当然了,…...

MQTT broker搭建并用SSL加密
系统为centos,基于emqx搭建broker,流程参考官方。 安装好后,用ssl加密。 进入/etc/emqx/certs,可以看到 分别为 cacert.pem CA 文件cert.pem 服务端证书key.pem 服务端keyclient-cert.pem 客户端证书client-key.pem 客户端key 编辑emqx配…...

深度剖析AI情感陪伴类产品及典型应用 Character.ai
前段时间AI圈内C.AI的受够风波可谓是让大家都丈二摸不着头脑,连C.AI这种行业top应用都要找谋生方法了!投资人摸不着头脑,用户们更摸不着头脑。在这之前断断续续玩了一下这款产品,这次也是乘着这个风波,除了了解一下为什…...

[数据集][目标检测]街头摊贩识别检测数据集VOC+YOLO格式758张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):758 标注数量(xml文件个数):758 标注数量(txt文件个数):758 标注类别…...

面试准备-3
BIO/NIO/AIO区别的区别? 同步阻塞IO : 用户进程发起一个IO操作以后,必须等待IO操作的真正完成后,才能继续运行。 同步非阻塞IO: 客户端与服务器通过Channel连接,采用多路复用器轮询注册的Channel。提高吞吐量和可靠性。用户进程发…...

Unity教程(十五)敌人战斗状态的实现
Unity开发2D类银河恶魔城游戏学习笔记 Unity教程(零)Unity和VS的使用相关内容 Unity教程(一)开始学习状态机 Unity教程(二)角色移动的实现 Unity教程(三)角色跳跃的实现 Unity教程&…...

利用深度学习实现验证码识别-3-ResNet18
在当今数字化时代,验证码作为一种重要的安全验证手段,广泛应用于各种网络场景。然而,传统的验证码识别方法往往效率低下,准确率不高。今天,我们将介绍一种基于 ResNet18 的验证码识别方法,它能够高效、准确…...

UDP通信实现
目录 前言 一、基础知识 1、跨主机传输 1、字节序 2、主机字节序和网络字节序 3、IP转换 2、套接字 3、什么是UDP通信 二、如何实现UDP通信 1、socket():创建套接字 2、bind():绑定套接字 3、sendto():发送指定套接字文件数据 4、recvfrom():接收指定地址信息的数据 三…...