linux应用编程笔记(14)共享内存编程

摘要: 总结了共享内存的定义,给出了使用共享内存的使用步骤,分析了使用共享内存需要使用的shmget,shmat,shmdt,shmctl函数,最后给出一个实例加深理解。


一、什么是共享内存

   这个字面意思其实就已经很好理解了,就是多个进程共享同一块内存,这个我们一个进程往这个内存中写入一定的数据,其他进程就可以立即受到反馈,可以去读取,访问,或者作出什么修改。共享内存就是被多个进程共享的一部分物理内存。共享内存是进程间共享数据最快的一种方式,一个进程向共享内存写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容,如下图。

    不过这里我有一个疑问,就像之前我们学习信号量的时候一样,假如有多个进程共享这一片内存,然后在同一时刻都要往里写东西,如何去同步是一个问题,好在可以使用信号量来使他们同步。

   


二、使用共享内存的步骤

    其实真正使用共享内存的步骤应该是稍微复杂一些的,因为涉及到各个进程之间的同步问题。这里为了学习和理解共享内存,所以只有以下两个步骤:

    1.创建共享内存,使用shmget函数。

    2.映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数。


三、共享内存函数学习

1.创建共享内存

函数名shmget

函数原型int shmget(key_t key,int size,int shmflg);

函数功能获取共享内存的标识符

           当key键值指定的共享内存不存在,并且key值等于IPC_PRIVATE的时候,就创建新的共享内存,并和键值关联,当key=0的时候,shmflg等于IPC_PRIVATE的时候,也创建新的共享内存,返回与之对应的标识符。

头文件#include <sys/ipc.h> #include <sys/shm.h>

返回值成功返回共享内存的标识符,失败返回-1

参数说明

    1.key_t key

   这个键值其实和信号量很像,之前在信号量详解及互斥编程里关于什么是键值我想应该介绍的很清楚了,key可以取0和IPC_PRIVATE两个值,当key取值为IPC_PRIVATE的时候,就会创建一块新的共享内存,当key=0,但是后面shmflg取IPC_PRIVATE的时候,也会创建一块新的共享内存。

    2.int size

    指定出我们需要共享的内存有多大。

    3.int shmflg

    权限标志,可以与IPC_CREAT或操作,进行创建。


2.映射共享内存

函数名shmat

函数原型void *shmat(int shmid,const void *shmaddr,int shmflg);

函数功能将shmid标识符代表的共享内存映射到进程可以使用的地址空间中去。

头文件#include <sys/types.h> #include <sys/shm.h>

返回值成功返回指向该共享内存的指针,失败返回(void *)-1,这里是man 2 shmat出来的结果,这个-1前面为什么要加void *应该是和对应的类型相关。

参数说明

   1.int shmid

    这个是上一个函数返回的共享内存的标识符,类比我们的文件句柄fd

   2.const void *shmaddr

    这里是表示共享内存映射到我们当前进程地址空间的什么位置,一般是空,表示让系统自己来选择。

   3.int shmflg

    以什么方式来确定映射的地址,一般为0。


3.分离共享内存

函数名shmdt

函数原型int shmdt(const void *shmaddr);

函数功能将shmaddr指向的共享内存从当前进程地址空间分离,这个操作并不是就删除了共享内存,而是将其分离,表示当前进程不能再使用它。

头文件#include <sys/types.h> #include <sys/shm.h>

返回值成功返回0,失败返回-1.

参数说明

    1.const void *shmaddr

    之前shmat返回的地址指针。


4.删除共享内存(控制)

函数名shmctl

函数原型int shmctl(int shmid,int cmd,struct shmid_ds*buf);

函数功能对共享内存进行控制,就像之前学习信号量的时候的函数,可以删除,设置权限等。

头文件#include <sys/ipc.h> #include <sys/shm.h>

返回值如果未设置特殊标识,一般成功返回0,失败返回-1.

参数说明

   1.int shmid

    shmget返回的共享内存标识符。

   2.int cmd

    这个取值有很多,我们这里为了删除使用的是IPC_RMID,别的还有IPC_SET,IPC_STAT。

   3.struct shmid_ds *buf

    一般为0,这里是一个与前两个参数都有关的结构体,具体做什么我还没有深入的研究。


四、实例分析

<span style="font-size:18px;">#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
 
#define PERM S_IRUSR|S_IWUSR//定义下面的创建的共享内存的权限
 
int main(int argc,char* argv[])
{
    int shmid;//用于返回共享内存的标识符
    char *p_addr,*c_addr;//两个地址指针,分别用于父子进程
   
    /*对输入参数进行检测*/
    if(argc!=2)
       {
           fprintf(stderr,"Usage:%s\n\a",argv[0]);
           exit(1);
           }
          
    /*创建共享内存*/    
    if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1)   
           {
              fprintf(stderr,"Creatshare memory failed%s\n\a",strerror(errno));
              exit(1);
              }
   
    /*创建父子进程利用共享内存进行通信*/     
    if(fork())//fork返回值,父进程中返回子进程大于零的id,子进程中返回0
       {
           p_addr=shmat(shmid,0,0);//将前面创建的共享内存标识符给shmat函数,第二个参数0是让系统自动分配地址,最后的0一般默认
           memset(p_addr,'\0',1024);//将共享内存清零
           strncpy(p_addr,argv[1],1024);//将运行时,输入的第二个参数拷贝到p_addr指向的共享内存中
           wait(NULL);//释放资源,不关心终止状态
           exit(0);//
           }
       else//子进程部分,我们将其读出来
           {
               sleep(1);//睡眠一秒,也是为了父进程执行完操作
              c_addr=shmat(shmid,0,0);//这样子进程就和父进程指向了同一块共享内存
              printf("We Client Get:%s\n",c_addr);
              exit(0);
              }
    }</span>

编译运行之后,结果如下:

    说明我们的子进程拿到了父进程往共享内存里面写的东西,当然这个程序是不安全,也是不完善的,这里只是为了理解共享内存的用法。


五、1个问题

1.什么是fprintf

函数名:fprintf

函数原型:int fprintf(FILE* stream, const char*format, [argument])

函数功能:传送格式化输出到一个文件中与打印机输出,这里是把错误传给stderr.

参数说明:

1.FILE*stream:文件指针

2.const char* format:输出格式

3.[argument]:附加参数列表

    这里我们使用fprintf是把错误的消息格式化输出到stderr文件中


    这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值