龙空技术网

Linux下的共享内存编程

源事件 89

前言:

眼前朋友们对“简述共享内存使用过程及其特点”大致比较关切,兄弟们都需要了解一些“简述共享内存使用过程及其特点”的相关知识。那么小编也在网上网罗了一些有关“简述共享内存使用过程及其特点””的相关知识,希望我们能喜欢,姐妹们快快来了解一下吧!

前面带小伙伴们学习了共享内存相关的内容,先简单介绍下共享内存,然后进行结构及函数的学习,最后撸代码使用一下这些函数使用一下共享内存,希望对大家有所帮助哈!

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。

运行结果如下:

文章转自:嵌入式杂牌军

标签: #简述共享内存使用过程及其特点