Linux中如何共享内存
这篇文章给大家分享的是有关Linux中如何共享内存的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
1 共享内存的概念及使用过程
1)共享内存的概念
共享内存是IPC机制中的一种。
共享内存:即允许两个或多个进程共享一个给定的存储区。
2)共享内存的使用过程
① 进程1创建共享内存,接着映射共享内存。
② 进程2获取共享内存,映射共享内存。
③ 交互完成,进程1分离共享内存,进程2分离共享内存。
④ 进程1删除共享内存。
2 共享内存相关的结构及函数
0)共享内存相关的结构
内核为每个共享存储段维护着一个结构,该结构至少要为每个共享存储段包含以下成员。
struct shmid_ds { struct ipc_perm shm_perm; // 操作权限 size_t shm_segsz; // 段的大小(以字节为单位) time_t shm_atime; // 上一个进程附加到该段的时间 time_t shm_dtime; // 上一个进程分离开该段的时间 time_t shm_ctime; // 上一个进程修改该段的时间 pid_t shm_cpid; // 创建该段进程的PID pid_t shm_lpid; // 上个shmat(2)/shmdt(2)的PID shmatt_t shm_nattch; // 当前附加到该段的进程的个数 ... };
系统为每一个IPC对象保存一个ipc_perm结构体,该结构说明了IPC对象的权限和所有者,每一个版本的内核各有不用的ipc_perm结构成员。
struct ipc_perm { key_t __key; // 为 shmget(2) 调用提供的键值 uid_t uid; // 共享内存所有者的有效用户UID gid_t gid; // 共享内存所有者所属组的有效组GID uid_t cuid; // 共享内存创建者的有效用户UID gid_t cgid; // 共享内存创建者所属组的有效组ID unsigned short mode; // 特权 + SHM_DEST 和SHM_LOCKED 标志 unsigned short __seq; // 序列号 };
1)shmget函数
shmget函数用于创建或者获取共享内存,并返回其描述符id。
① 函数原型。
int shmget(key_t key,size_t sizie,int shmflg)
② 头文件。
includeinclude
③ 参数。
key:共享内存的键值。
size:共享内存的大小。
shmflg:打开标志,如果使用了IPC_CREAT,则会新创建一块共享内存。
④ 返回值。
成功:返回创建或者获取到的共享内存的描述符。
失败:-1。
2)shmat函数
shmat函数用于映射共享内存,即将进程连接到它的地址空间。
① 函数原型。
void *shmat(int shmid,const void *shmaddr,int shmflg)
② 头文件。
includeinclude
③ 参数。
shmid:要映射的共享内存的描述符。
shmaddr:共享内存的地址。
shmflg:打开标志,如果使用了IPC_CREAT,则会新创建一块共享内存。
④ 返回值。
成功:返回创建或者获取到的共享内存的描述符。
失败:-1。
3)shmdt函数
shmdt函数用于分离共享内存,即操作完存储段后,用此函数可以将进程与此存储段脱离开,即断掉与共享内存的联系。
① 函数原型。
int shmdt(const void *shmaddr)
② 头文件。
#include#include
③ 参数。
shmaddr:要断开的共享内存的映射地址。
④ 返回值。
成功:0。
失败:-1。
4)shmctl函数
shmctl函数用于控制共享内存,通过参数可以对共享内存进行特定的操作。
① 函数原型。
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
② 头文件。
#include#include
③ 参数。
shmid:要控制的共享内存的id。
cmd:决定执行什么样的控制操作,如IPC_RMID(表示删除)。
buf:获取linux中描述共享内存的shmid_ds结构。基本不使用。
cmd可去的参数如下,需要参照上面的结构shmid_ds和ipc_perm :
IPC_STAT:取此段的shmid_ds结构,并将它存储在由buf指向的结构中。
IPC_SET:按buf指向的结构中的值设置与此共享存储段相关的shmid_ds结构中的下列3个字段:shmperm.uid、shm perm.gid和shmperm.mode。
此命令只能由下列两种进程执行:一种是其有效用户ID等于shm_perm.cuid或shmperm.uid的进程;另一种是具有超级用户特权的进程。
IPC_RMID:从系统中删除该共享存储段。
除非使用该段的最后一个进程终止或与该段分离,否则不会实际上删除该存储段。
不管此段是否仍在使用,该段标识符都会被立即删除,所以不能再用shmat与该段连接。
此命令只能由下列两种进程执行:一种是其有效用户ID等于shm_perm.cuid或shm_perm.uid的进程;另一种是具有超级用户特权的进程。
下面两个命令只能由超级用户执行:
SHM_LOCK:在内存中对共享存储段加锁。
SHM_UNLOCK:解锁共享存储段。
④ 返回值。
成功:根据不同的操作返回不同的值。
失败:-1。
3 实例代码
下面用两个进程,给大家演示下共享内存的使用过程。
实例代码如下,说明都在代码注释中了。
WriteMemory.c。
#include#include #include #include #include #include #include #define SIZE 1024 // 可输入1K字符串 struct SharedMemoryST { int ReadWriteFlag; // 表明是谁放进去的 char CharData[SIZE]; // 字符数组保存用户输入数据 }; int main(int argc,char *argv[]) { int shmid; int ReadStatusFlag = 1; // 内存中数据是否被读走,1未被读走 struct SharedMemoryST *shm; // 共享内存结构变量 char buffer[SIZE]; key_t key=ftok("/tmp",12); // 创建共享内存的键值,如果提示创建失败(一般是没有quit引起的),可以修改读写进程的键值,都要改成同一数字 //1 创建共享内存 shmid = shmget(key,sizeof(struct SharedMemoryST),IPC_CREAT|IPC_EXCL|0777); if(shmid == -1) // 如果创建失败 { printf("\nCreating share memory fail!\n\n"); exit(1); } //2 映射共享内存 shm = shmat(shmid,NULL,0); // 内存id,映射的位置,映射的标志(此无特殊要求) //3 查询写入的 while(ReadStatusFlag) // 循环检查写入共享内存的数据是否被读走,读走后退出循环 { while(shm->ReadWriteFlag == 1) { sleep(1); printf("\nWaiting read memory!\n"); } // 获取用户输入 printf("\nPlease input data or input 'quit' to exit!\n\n"); fgets(buffer,SIZE,stdin); // 参数:字符串的位置,长度,获取的方式位置 // 将用户输入的字符串放入共享内存 strncpy(shm->CharData,buffer,SIZE);// 参数:目的数据,源数据,数据大小 shm->ReadWriteFlag = 1; if(strncmp(buffer,"quit",4) == 0) // 最后一个参数为比较字符的数量 { ReadStatusFlag = 0; // 写入共享内存的数据已经被读走 } } //4 脱离共享存 shmdt((const void *)shm); return 0; }
ReadMemory.c。
#include#include #include #include #include #include #define SIZE 1024 // 可输入1K字符串 struct SharedMemoryST { int ReadWriteFlag; // 标明是读进程还是写进程放入了数据 char CharData[SIZE]; // 保存用户输入数据 }; int main(int argc,char *argv[]) { int shmid; int ReadStatusFlag = 1; // 内存中数据是否被读走的标志位,1表示未被读走 struct SharedMemoryST *shm; // 共享内存结构 key_t key=ftok("/tmp",12); // 创建共享内存的键值,如果提示创建失败,修改一下数字即可,读写进程都要改成同一数字 //1 创建/获取共享内存 shmid = shmget(key,sizeof(struct SharedMemoryST),IPC_CREAT|0777);//分配大小为结构大小,1234是随便给的键值 //2 映射共享内存 shm = (struct SharedMemoryST *)shmat(shmid,NULL,0); //内存id,映射的位置,映射的标志(此无特殊要求) shm->ReadWriteFlag = 0; //3 检查是否收到信息,收到quit退出 while(ReadStatusFlag) { //打印共享内存 if(shm->ReadWriteFlag == 1) // 等于说明有相应的数据 { printf("\nThe write context is: %s\n",shm->CharData); shm->ReadWriteFlag = 0; if(strncmp(shm->CharData,"quit",3) == 0) { ReadStatusFlag = 0; // 结束查询,退出 } } } //4 脱离共享内存 shmdt((const void *)shm); //5 删除共享内存 shmctl(shmid,IPC_RMID,0); }
写共享内存先创建共享内存,写入数据,读共享内存读取数据,通过标志查询方式,退出输入quit。
运行结果如下:
感谢各位的阅读!关于"Linux中如何共享内存"这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!