共计 4738 个字符,预计需要花费 12 分钟才能阅读完成。
这篇文章给大家分享的是有关 Linux 中如何共享内存的内容。丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,一起跟随丸趣 TV 小编过来看看吧。
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)
② 头文件。
include sys/ipc.h include sys/shm.h
③ 参数。
key: 共享内存的键值。
size: 共享内存的大小。
shmflg: 打开标志,如果使用了 IPC_CREAT,则会新创建一块共享内存。
④ 返回值。
成功:返回创建或者获取到的共享内存的描述符。
失败:-1。
2)shmat 函数
shmat 函数用于映射共享内存,即将进程连接到它的地址空间。
① 函数原型。
void *shmat(int shmid,const void *shmaddr,int shmflg)
② 头文件。
include sys/types.h include sys/shm.h
③ 参数。
shmid: 要映射的共享内存的描述符。
shmaddr: 共享内存的地址。
shmflg: 打开标志,如果使用了 IPC_CREAT, 则会新创建一块共享内存。
④ 返回值。
成功:返回创建或者获取到的共享内存的描述符。
失败:-1。
3)shmdt 函数
shmdt 函数用于分离共享内存,即操作完存储段后,用此函数可以将进程与此存储段脱离开,即断掉与共享内存的联系。
① 函数原型。
int shmdt(const void *shmaddr)
② 头文件。
#include sys/types.h #include sys/shm.h
③ 参数。
shmaddr: 要断开的共享内存的映射地址。
④ 返回值。
成功:0。
失败:-1。
4)shmctl 函数
shmctl 函数用于控制共享内存,通过参数可以对共享内存进行特定的操作。
① 函数原型。
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
② 头文件。
#include sys/ipc.h #include sys/shm.h
③ 参数。
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 sys/types.h #include sys/shm.h
#include sys/ipc.h #include stdio.h #include unistd.h #include stdlib.h #include string.h #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 sys/types.h #include sys/shm.h
#include sys/ipc.h #include stdio.h #include unistd.h #include stdlib.h #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 中如何共享内存”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!