Linux下的共享内存编程

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

[[385298]]

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

 

1 共享内存的概念及使用过程

1)共享内存的概念

共享内存是IPC机制中的一种。

共享内存:即允许两个或多个进程共享一个给定的存储区。

2)共享内存的使用过程

① 进程1创建共享内存,接着映射共享内存。

② 进程2获取共享内存,映射共享内存。

③ 交互完成,进程1分离共享内存,进程2分离共享内存。

④ 进程1删除共享内存。

2 共享内存相关的结构及函数

0)共享内存相关的结构

内核为每个共享存储段维护着一个结构,该结构至少要为每个共享存储段包含以下成员。

  1. struct shmid_ds  
  2.      struct ipc_perm shm_perm;    // 操作权限  
  3.      size_t          shm_segsz;   // 段的大小(以字节为单位)  
  4.      time_t          shm_atime;   // 上一个进程附加到该段的时间  
  5.      time_t          shm_dtime;   // 上一个进程分离开该段的时间 
  6.      time_t          shm_ctime;   // 上一个进程修改该段的时间  
  7.      pid_t           shm_cpid;    // 创建该段进程的PID  
  8.      pid_t           shm_lpid;    // 上个shmat(2)/shmdt(2)的PID  
  9.      shmatt_t        shm_nattch;  // 当前附加到该段的进程的个数  
  10.      ... 
  11. }; 

系统为每一个IPC对象保存一个ipc_perm结构体,该结构说明了IPC对象的权限和所有者,每一个版本的内核各有不用的ipc_perm结构成员。

  1. struct ipc_perm  
  2.      key_t          __key;    // 为 shmget(2) 调用提供的键值 
  3.      uid_t          uid;      // 共享内存所有者的有效用户UID  
  4.      gid_t          gid;      // 共享内存所有者所属组的有效组GID  
  5.      uid_t          cuid;     // 共享内存创建者的有效用户UID  
  6.      gid_t          cgid;     // 共享内存创建者所属组的有效组ID  
  7.      unsigned short mode;     // 特权 + SHM_DEST 和SHM_LOCKED 标志  
  8.      unsigned short __seq;    // 序列号 
  9. }; 

1)shmget函数

shmget函数用于创建或者获取共享内存,并返回其描述符id。

① 函数原型。

  1. int shmget(key_t key,size_t sizie,int shmflg) 

② 头文件。

  1. include <sys/ipc.h>  
  2.  
  3. include <sys/shm.h>  

③ 参数。

key:共享内存的键值。

size:共享内存的大小。

shmflg:打开标志,如果使用了IPC_CREAT,则会新创建一块共享内存。

④ 返回值。

成功:返回创建或者获取到的共享内存的描述符。

失败:-1。

2)shmat函数

shmat函数用于映射共享内存,即将进程连接到它的地址空间。

① 函数原型。

  1. void *shmat(int shmid,const void *shmaddr,int shmflg) 

② 头文件。

  1. include <sys/types.h>  
  2.  
  3. include <sys/shm.h>  

③ 参数。

shmid:要映射的共享内存的描述符。

shmaddr:共享内存的地址。

shmflg:打开标志,如果使用了IPC_CREAT,则会新创建一块共享内存。

④ 返回值。

成功:返回创建或者获取到的共享内存的描述符。

失败:-1。

3)shmdt函数

shmdt函数用于分离共享内存,即操作完存储段后,用此函数可以将进程与此存储段脱离开,即断掉与共享内存的联系。

① 函数原型。

  1. int shmdt(const void *shmaddr) 

② 头文件。

  1. #include <sys/types.h> 
  2.  
  3. #include <sys/shm.h>  

③ 参数。

shmaddr:要断开的共享内存的映射地址。

④ 返回值。

成功:0。

失败:-1。

4)shmctl函数

shmctl函数用于控制共享内存,通过参数可以对共享内存进行特定的操作。

① 函数原型。

  1. int shmctl(int shmid, int cmd, struct shmid_ds *buf) 

② 头文件。

  1. #include <sys/ipc.h> 
  2.  
  3. #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。

  1. #include <sys/types.h> 
  2. #include <sys/shm.h> 
  3. #include <sys/ipc.h> 
  4. #include <stdio.h> 
  5. #include <unistd.h> 
  6. #include <stdlib.h> 
  7. #include <string.h> 
  8.  
  9. #define SIZE 1024                              // 可输入1K字符串 
  10.  
  11.  
  12. struct SharedMemoryST 
  13. {  
  14.       int ReadWriteFlag;                       // 表明是谁放进去的 
  15.       char CharData[SIZE];                     // 字符数组保存用户输入数据 
  16. }; 
  17.  
  18. int main(int argc,char *argv[]) 
  19.       int shmid; 
  20.       int ReadStatusFlag = 1;                 // 内存中数据是否被读走,1未被读走 
  21.       struct SharedMemoryST *shm;             // 共享内存结构变量 
  22.       char buffer[SIZE]; 
  23.   
  24.       key_t key=ftok("/tmp",12);              // 创建共享内存的键值,如果提示创建失败(一般是没有quit引起的),可以修改读写进程的键值,都要改成同一数字 
  25.  
  26.       //1 创建共享内存 
  27.       shmid = shmget(key,sizeof(struct SharedMemoryST),IPC_CREAT|IPC_EXCL|0777); 
  28.       if(shmid == -1)                         // 如果创建失败 
  29.       { 
  30.            printf("\nCreating share memory fail!\n\n"); 
  31.            exit(1); 
  32.       } 
  33.  
  34.       //2 映射共享内存 
  35.       shm = shmat(shmid,NULL,0);              // 内存id,映射的位置,映射的标志(此无特殊要求) 
  36.  
  37.  
  38.       //3 查询写入的 
  39.       while(ReadStatusFlag)                   // 循环检查写入共享内存的数据是否被读走,读走后退出循环 
  40.       { 
  41.            while(shm->ReadWriteFlag == 1) 
  42.            { 
  43.                 sleep(1); 
  44.                 printf("\nWaiting read memory!\n"); 
  45.            } 
  46.    
  47.            // 获取用户输入 
  48.            printf("\nPlease input data or input 'quit' to exit!\n\n"); 
  49.            fgets(buffer,SIZE,stdin);          // 参数:字符串的位置,长度,获取的方式位置 
  50.    
  51.            // 将用户输入的字符串放入共享内存 
  52.            strncpy(shm->CharData,buffer,SIZE);// 参数:目的数据,源数据,数据大小 
  53.    
  54.            shm->ReadWriteFlag = 1; 
  55.  
  56.            if(strncmp(buffer,"quit",4) == 0)  // 最后一个参数为比较字符的数量 
  57.            { 
  58.                 ReadStatusFlag = 0;           // 写入共享内存的数据已经被读走 
  59.            } 
  60.  
  61.       } 
  62.  
  63.       //4 脱离共享存 
  64.       shmdt((const void *)shm); 
  65.  
  66.       return 0;                

ReadMemory.c。

  1. #include <sys/types.h> 
  2. #include <sys/shm.h> 
  3. #include <sys/ipc.h> 
  4. #include <stdio.h> 
  5. #include <unistd.h> 
  6. #include <stdlib.h> 
  7.  
  8. #define SIZE 1024                        // 可输入1K字符串 
  9.  
  10. struct SharedMemoryST 
  11.      int ReadWriteFlag;                  // 标明是读进程还是写进程放入了数据 
  12.      char CharData[SIZE];                // 保存用户输入数据 
  13. }; 
  14.  
  15. int main(int argc,char *argv[]) 
  16.      int shmid; 
  17.      int ReadStatusFlag = 1;            // 内存中数据是否被读走的标志位,1表示未被读走 
  18.      struct SharedMemoryST *shm;        // 共享内存结构 
  19.    
  20.      key_t key=ftok("/tmp",12);         // 创建共享内存的键值,如果提示创建失败,修改一下数字即可,读写进程都要改成同一数字 
  21.   
  22.    
  23.      //1 创建/获取共享内存 
  24.      shmid = shmget(key,sizeof(struct SharedMemoryST),IPC_CREAT|0777);//分配大小为结构大小,1234是随便给的键值 
  25.  
  26.      //2 映射共享内存 
  27.      shm = (struct SharedMemoryST *)shmat(shmid,NULL,0);              //内存id,映射的位置,映射的标志(此无特殊要求) 
  28.  
  29.      shm->ReadWriteFlag = 0; 
  30.  
  31.      //3 检查是否收到信息,收到quit退出 
  32.      while(ReadStatusFlag) 
  33.      { 
  34.           //打印共享内存 
  35.          if(shm->ReadWriteFlag == 1)    // 等于说明有相应的数据 
  36.          {  
  37.               printf("\nThe write context is: %s\n",shm->CharData); 
  38.               shm->ReadWriteFlag = 0; 
  39.        
  40.               if(strncmp(shm->CharData,"quit",3) == 0) 
  41.               { 
  42.                     ReadStatusFlag = 0; // 结束查询,退出 
  43.               } 
  44.          } 
  45.      } 
  46.  
  47.      //4 脱离共享内存 
  48.      shmdt((const void *)shm); 
  49.  
  50.      //5 删除共享内存 
  51.      shmctl(shmid,IPC_RMID,0); 

写共享内存先创建共享内存,写入数据,读共享内存读取数据,通过标志查询方式,退出输入quit。

运行结果如下:

本文转载自微信公众号「嵌入式杂牌军」,可以通过以下二维码关注。转载本文请联系嵌入式杂牌军公众号。

 

责任编辑:武晓燕 来源: 嵌入式杂牌军
相关推荐

2020-10-09 07:13:11

Linux系统编程mmap

2018-01-12 14:35:00

Linux进程共享内存

2009-12-14 17:13:04

Linux系统修改共享

2019-05-08 11:10:05

Linux进程语言

2017-08-14 13:35:36

Linux共享内存tmpfs文件系统

2013-11-26 16:05:24

Linux共享内存

2021-10-06 20:23:08

Linux共享内存

2021-03-08 08:55:41

Linux内存命令

2022-06-07 12:03:33

Java内存模型

2009-08-08 09:50:30

Linux操作系统共享内存Linux

2023-07-06 00:45:05

Linux保护模式

2009-04-24 10:57:25

2013-04-09 14:49:18

Linux内存统计内存泄露

2010-06-11 11:15:33

Linux编程工具

2017-04-13 13:00:27

LinuxWindowstomcat

2010-09-27 15:03:34

TomcatJVM内存设置

2020-11-06 18:51:17

LinuxTCP服务器

2009-04-24 14:56:24

2010-07-20 16:30:44

MySQL内存

2010-01-11 09:28:34

C++编程
点赞
收藏

51CTO技术栈公众号