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

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...

结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...