下面我们将代码运行起来测试一下:
我们将程序运行起来发现并没有问题,下面我们查看共享内存是否创建成功,ipcs这个命令可以显示出三条资源:
第一条资源为消息队列,第二条资源为共享内存段,第三个为共享内存核心数组,我们主要看第二条,可以看到我们创建的1024大小的共享内存创建成功了。当然我们可以只查第二条,命令是ipcs -m :
下面我们讲一下上面所代表的意思,key就像文件的inode一样,而shmid就像文件的fd一样shmid才是操作共享内存所需要的核心数据。owner是谁创建的,perms是权限,nattch是与这个共享内存的连接数。下面我们在讲一下删除一个共享内存的命令:ipcrm -m +shmid(刚刚讲过shmid是用来操作共享内存的,与文件的fd作用一样):
我们成功的删除了刚刚创建的共享内存。我们接着代码往下写,创建了共享内存后可以让客户端往服务端写一些东西,然后退出的时候需要删除共享内存,我们先来看看如何删除共享内存:
利用系统调用删除共享内存需要shmctl函数,第一个参数就是共享内存的shmid,第二个参数是指令,也就是说对共享内存做什么操作,我们看看指令有哪些:
常见的指令有这么几个,而IPC_RMID就是真正删除共享内存的操作,第一个IPC_STAT是获取共享内存的属性,而第三个参数是一个共享内存的结构体的指针可以查看共享内存对应的属性:
下面我们就写一个删除共享内存函数:
void delshm(int shmid) { int n = shmctl(shmid,IPC_RMID,nullptr); assert(n!=-1); (void)n; }
因为我们删除共享内存的时候不关心它的属性,所以我们直接设为空即可。
下面我们给大家演示一下查看共享内存的属性:
下面我们可以在创建共享内存的时候将权限也设置好:
int creatShm(key_t k,int size) { umask(0); return createShmHelper(k,size,IPC_CREAT|IPC_EXCL|0666); }
下面我们要将创建出来的共享内存与进程关联起来,要关联得需要shmat函数:
第一个参数我们都知道,第二个参数的意思是可以指定将共享内存挂接到指定的地址处(在这里可以设为nullptr,nullptr后操作系统会自己选择合适的地址挂接),第三个参数是设置共享内存是只读的还是什么其他的权限(我们可以设为0,设为0默认是可读可写)
char* attachShm(int shmid) { char* start = (char*)shmat(shmid,nullptr,0); return start; }
当我们将进程和共享内存关联后,下一步就是退出前将他们去关联,去关联同样也需要函数,这个函数是shmdt:
这个函数的参数我们已经讲过了,就是刚刚关联时候给我们返回的那个地址,所以我们可以直接写代码了:
void detachShm(char* start) { int n = shmdt(start); assert(n!=-1); (void)n; }
以上内存的所有点我们就讲完了,下面我们通过一个类封装一下让客户端和服务端的代码可以少一些:
#define SERVER 1 #define CLIENT 0 class Init { public: Init(int type) { key_t k = getKey(); if (type==SERVER) { shmid = creatShm(k,gsize); } else { shmid = getShm(k,gsize); } start = attachShm(shmid); } char* getStart() { return start; } ~Init() { detachShm(start); if (type==SERVER) { delShm(shmid); } } private: char* start; int type; int shmid; }
通过以上类的封装,我们的客户端和服务端就能简化为以下这样:
我们可以看到当我们一开始两个端口都运行的时候有两个进程链接在共享内存上,当客户端指令输入完成退出后就只剩下服务端,当服务端也退出后那么连接数就为0了。
以上就是我们共享内存的所有内容,学了共享内存要知道共享内存是进程间通信的几种方式中访问速度最快的。
总结
使用ipcrm -m 命令删除指定共享内存后,是不会直接释放共享内存的,因为共享内存的生命周期是随操作系统的,只有共享内存当前的映射链接数为0才会被删除释放。
使用ipcrm -a 可以删除所有进程间通信资源(a代表all也就是全部的意思)
ipcrm -m删除共享内存,-q删除消息队列,-s删除信号量
共享内存实现实现通信的原理是因为所有进程操作映射同一块物理内存。
共享内存的操作是非进程安全的,多个进程同时对共享内存读写是有可能造成数据的交叉写入或读取,造成数据混乱。
共享内存的删除操作并非是直接删除,而是拒绝后续映射,只有在当前映射链接数为0的时候表示没有进程访问了,才会真正的被删除。
共享内存生命周期随内核,只要不删除,就一直存在于内核中,除非重启系统或者手动删除。