专业网站策划 西安,上海网站推广排名公司,番禺做网站哪家强,公司行政负责做网站吗文章目录 共享内存(Share Memory)信号队列#xff08;Message Queue#xff09;信号量(semaphore) 进程间通信的核心理念#xff1a;让不同的进程看见同一块资源 linux下的通信方案#xff1a;
SYSTEM V 共享内存(Share Memory)
特点#xff1a;1.共享内存是进程见通信最… 文章目录 共享内存(Share Memory)信号队列Message Queue信号量(semaphore) 进程间通信的核心理念让不同的进程看见同一块资源 linux下的通信方案
SYSTEM V 共享内存(Share Memory)
特点1.共享内存是进程见通信最最快的 2.可以提供较大通信空间 注意共享内存由于裸露给所有使用者因此是需要维护的
做法去申请一块空间让其映射到对应的不同进程的进程地址空间。 如图
那么具体是怎么做的呢
linux是生成一个特定的key,有key作为表示这块共享内存的唯一标识。不同进程在运行的时候凭借这个key拿到共享内存的shmid(类似于文件管理系统的fd)进行挂接到自己的进程地址空间上。申请的空间是不会自己释放的要么在程序里面用funtion控制要么在外部手动释放 ipcs -m #查看当前有哪些共享内存 ipcrm -m shmid #删除对应的共享内存id
需要用到的系统调用 shmget #创建共享内存 shmat # 挂接共享内存 shmdt # 取消挂接 shmctl # 操控这块共享内存 unlink # 删除文件 server:
#include Common.hppclass Init
{
public:Init(){bool r MakeFifo();//用管道是为了进程进行时具备一定顺序性。if (!r)return;key_t key GetKey();shmid CreatShm(key);std::cout shmid: shmid \n;// sleep(5);std::cout 开始将shm映射到进程地址空间\n;s (char *)shmat(shmid, nullptr, 0);fd open(filename.c_str(), O_RDONLY);}~Init(){close(fd);std::cout 将shm从进程地址空间移除\n;shmdt(s);std::cout 将共享内存从操作系统中释放\n;shmctl(shmid, IPC_RMID, nullptr);unlink(filename.c_str());}int FileDirection(){return fd;}const char *ShnPtr(){return s;}private:int shmid;int fd;char *s;
};int main()
{Init init;// struct shmid_ds ds;// std::coutstd::hexds.shm_perm.__key\n;// std::coutds.shm_nattch\n;while (true){int code 0;ssize_t n read(init.FileDirection(), code, sizeof(code));if (n 0){std::cout 共享读取 init.ShnPtr() \n;}else if (n 0){break;}else{std::cerr 读取错误错误码 errno \n;}}return 0;
}client
#include Common.hppint main()
{key_t key GetKey();int shmid CreatShmHelper(key, IPC_CREAT | 0644);char *s static_castchar *(shmat(shmid, nullptr, 0));std::cout attach shm done\n;int fd open(filename.c_str(), O_WRONLY);for (int c 0; c 26; c){s[c] c a;std::cout write: (char)c a done\n;sleep(1);int code 1;write(fd, (char *)code, sizeof(code));}// sleep(5);std::cout dettach shm done\n;shmdt(s);close(fd);return 0;
}
.h #pragma once#include iostream
#include string
#include cstdlib
#include unistd.h
#include cassert
#include cstring
#include sys/types.h
#include sys/stat.h
#include sys/ipc.h
#include sys/shm.h
#include fcntl.hconst std::string pathname ./Common.hpp;//这里选择一起的头文件作为生成Key的路径文件即可
const int proj_id 0x234;
const int size 4096;
const std::string filename fifo;
key_t GetKey()
{key_t key ftok(pathname.c_str(), proj_id);if (key 0){std::cerr errno: errno ,errnostring: std::strerror(errno) std::endl;exit(-1);}return key;
}int CreatShmHelper(key_t key, int flag)
{int shmid shmget(key, size, flag); //共享内存也有权限也是需要设置的// EXCL保证创建时如果存在就会失败if (shmid 0){std::cerr errno: errno ,errnostring: std::strerror(errno) std::endl;exit(2);}return shmid;
}int CreatShm(key_t key)
{return shmget(key, size, IPC_CREAT | IPC_EXCL | 0644); //共享内存也有权限也是需要设置的
}int GetShm(key_t key)
{return shmget(key, size, IPC_CREAT); //共享内存也有权限也是需要设置的
}//为1创建成功
bool MakeFifo()
{int n mkfifo(filename.c_str(), 0666);if (n 0){std::cerr errno: errno ,errstring strerror(errno) std::endl;return 0;}std::cout mkfifo success... std::endl;return 1;
}
信号队列Message Queue
基于SYSTEM V的还有对应的信号队列Message Queue信号量 下面展示下Message Queue的简单使用代码。
基本的系统调用函数在下面代码中有具体使用可以通过man手册查询。
#pragma once#include iostream
#include string
#include cstdlib
#include unistd.h
#include cassert
#include cstring
#include sys/types.h
#include sys/stat.h
#include sys/ipc.h
#include sys/shm.h
#include fcntl.h
#include sys/msg.h
key_t GetKey()
{key_t key ftok(pathname.c_str(), proj_id);if (key 0){std::cerr errno: errno ,errnostring: std::strerror(errno) std::endl;exit(-1);}return key;
}//消息队列也是存在于内核之中不手动关闭的生命周期和内核一起int main()
{key_t key GetKey();int msgid msgget(key,IPC_CREAT |IPC_EXCL);std::coutmsgid:msgid\n;struct msqid_ds ds;std::coutds.__msg_cbytes\n;std::coutds.msg_perm.__key\n;//用msgsend来发送消息//用msgrcv来接受消息msgctl(msgid,IPC_RMID,nullptr);//也可以 ipcrm -q msgid 在bash删除return 0;} 信号量(semaphore)
前置知识
公共资源多个执行流看见的同一份资源多个执行流访问同一份资源就存在并发访问为了解决并发访问公共资源的问题导致的数据不一致、脏读等问题需要保护资源因此引发出互斥和同步互斥同一时刻只能有一个执行流访问资源加锁完成同步多个执行流按照预定的先后次序来访问公共资源被保护起来的资源称为临界资源访问临界资源的执行流或者代码称为临界区 分析本质是个计数器当进程需要访问公共资源先获取信号量再去访问资源。相当于信号量是获取资源的凭证有了信号量就一定会有资源没获取信号量的进程就阻塞等待。信号量如果被获取了就没了没被获取就全部都在。是只有两种状态二元性的。因此由此二元性完成了互斥的功能不同的进程也需要看到同一份信号量因此信号量也被纳入IPC体系也就是说信号量由操作系统提供我们知道SYSTEM V的资源是可以看见的但是信号量是原子的(atomic,不可在分的)即使被进程竞争的访问也只会出现要么获取了要么没获取信号量。不会出现获取半个的情况。这种原子的获取操作称之为P操作。相对应原子的释放称之为V操作。 信号量系统调用 semget semctl semop linux内核看SYSTEM V设计的共享内存等通信方式 一般来说
内核里面有一个ipc_id_ary,其是一个柔性数组存储了一个size表示大小和指针数组size表示指针数组的个数这个指针数组所存的指针类型是 **kern_ipc_perm***的指针类型由SYSTEM V标准下设计出来的共享内存信号队列等内核里面都是由一个自己类型的结构体去管理的例如msg_queue就是管理信号队列的结构体Shmid_Kernel, 就是管理共享内存的结构体而这些结构体的第一个元素都被设计成相似的结构体信号队列是:q_perm,共享内存是shm_perm这些结构体所包含的元素类型其实和 kern_ipc_perm的结构体元素类型是一样的。这就使得我们存储kern_ipc_perm的指针即使存了msg_queue的结构体指针只需要通过强制类型转换也是可以访问msg_queue结构体这样对SYSYTEM V设计下的共享内存信号队列等可以统一管理 上面这种内核的设计实际就是利用了C语言的特点实现了多态有种通过父类指针访问子类的类似