2065|0

64

帖子

62

TA的资源

一粒金砂(高级)

楼主
 

linux 共享内存 [复制链接]

可以说,共享内存是一种最为高效的进程间通信方式,因为进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换信息,内核专门留出了一块内存区,这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据的复制,从而大大提高了效率。当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。其原理示意图如图1所示。

图1  共享内存原理示意图
    共享内存的实现分为两个步骤:第一步是创建共享内存,这里用到的函数是shmget(),也就是从内存中获得一段共享内存区域;第二步是映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,这里使用的函数是shmat()。到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O读写命令对其进行操作。除此之外,还有撤销映射的操作,其函数为shmdt()。这里主要介绍这3个函数。
    表1 列举了shmget()函数的语法要点。
表1  shmget()函数语法要点
所需头文件
#include
    #include
    #include
函数原型
int shmget(key_t key, int size, int shmflg)
函数传入值
key:共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC_PRIVATE,用于创建当前进程的私有共享内存
size:共享内存区大小
shmflg:同open()函数的权限位,也可以用八进制表示法
函数返回值
成功:共享内存段标识符
出错:-1
    表2列举了shmat()函数的语法要点。
表2  shmat()函数语法要点
所需头文件
#include
    #include
    #include
函数原型
char *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid:要映射的共享内存区标识符
shmaddr:将共享内存映射到指定地址(若为0则表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)
shmflg
SHM_RDONLY:共享内存只读
默认0:共享内存可读写
函数返回值
成功:被映射的段地址
出错:-1
    表3列举了shmdt()函数的语法要点。
表3  shmdt()函数语法要点
所需头文件
#include
    #include
    #include
函数原型
int shmdt(const void *shmaddr)
函数传入值
shmaddr:被映射的共享内存段地址
函数返回值
成功:0
出错:-1
    以下实例说明了如何使用基本的共享内存函数。首先创建一个共享内存区(采用的共享内存的键值为IPC_PRIVATE,是因为本实例中创建的共享内存是父子进程间的共用部分),然后创建子进程,在父子两个进程中将共享内存分别映射到各自的进程地址空间中。
    父进程先等待用户输入,然后将用户输入的字符串写入到共享内存,之后向共享内存的头部写入“WROTE”字符串表示父进程已成功写入数据。子进程一直等到共享内存的头部字符串为“WROTE”,然后将共享内存的有效数据(在父进程中用户输入的字符串)在屏幕上打印。父子两个进程在完成以上工作后,分别解除与共享内存的映射关系。
    最后在子进程中删除共享内存。因为共享内存自身并不提供同步机制,所以应额外实现不同进程间的同步(如信号量)。为了简单起见,在本实例中用标志字符串来实现非常简单的父子进程间的同步。
    这里要介绍的一个命令是ipcs,用于报告进程间通信机制状态,它可以查看共享内存、消息队列等各种进程间通信机制的情况,这里使用了system()函数调用shell命令“ipcs”。程序源代码如下:
    /* shmem.c */
        #include
        #include
        #include
        #include
        #include
        #include

            #define BUFFER_SIZE 2048

            int main()
        {
            pid_t pid;
            int shmid;
            char *shm_addr;
            char flag[] = "WROTE";
            char *buff;

                /* 创建共享内存 */
            if ((shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666)) < 0)
            {
                perror("shmget");
                exit(1);
            }
            else
            {
            printf("Create shared-memory: %d\n",shmid);
            }

                /* 显示共享内存情况 */
            system("ipcs -m");

                pid = fork();
            if (pid == -1)
            {
                perror("fork");
                exit(1);
            }
            else if (pid == 0) /* 子进程处理 */
            {
                /* 映射共享内存 */
                if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
                {
                    perror("Child: shmat");
                    exit(1);
                }
                else
                {
                    printf("Child: Attach shared-memory: %p\n", shm_addr);
                }
                system("ipcs -m");

                    /* 通过检查在共享内存的头部是否有标志字符串“WROTE”来确认父进程已经向共享内存写入有效数据 */
                while (strncmp(shm_addr, flag, strlen(flag)))
                {
                    printf("Child: Wait for enable data...\n");
                    sleep(5);
                }

                    /* 获取共享内存的有效数据并显示 */
                strcpy(buff, shm_addr + strlen(flag));
                printf("Child: Shared-memory :%s\n", buff);

                    /* 解除共享内存映射 */
                if ((shmdt(shm_addr)) < 0)
                {
                    perror("shmdt");
                    exit(1);
                }
                else
                {
                    printf("Child: Deattach shared-memory\n");
                }
                system("ipcs -m");

                    /* 删除共享内存 */
                if (shmctl(shmid, IPC_RMID, NULL) == -1)
                {
                    perror("Child: shmctl(IPC_RMID)\n");
                    exit(1);
                }
                else
                {
                    printf("Delete shared-memory\n");
                }

                    system("ipcs -m");
            }
            else /* 父进程处理 */
            {
                /* 映射共享内存 */
                if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
                {
                    perror("Parent: shmat");
                    exit(1);
                }
                else
                {
                    printf("Parent: Attach shared-memory: %p\n", shm_addr);
                }

                    sleep(1);
                printf("\nInput some string:\n");
                fgets(buff, BUFFER_SIZE, stdin);
                strncpy(shm_addr + strlen(flag), buff, strlen(buff));
                strncpy(shm_addr, flag, strlen(flag));

                    /* 解除共享内存映射 */
                if ((shmdt(shm_addr)) < 0)
                {
                    perror("Parent: shmdt");
                    exit(1);
                }
                else
                {
                    printf("Parent: Deattach shared-memory\n");
                }
                system("ipcs -m");

                    waitpid(pid, NULL, 0);               
                printf("Finished\n");
            }

                exit(0);
        }     
    下面是运行结果,从该结果中可以看出,nattch的值随着共享内存状态的变化而变化,共享内存的值根据不同的系统会有所不同。
    $ ./shmem
        Create shared-memory: 753665
        /* 在刚创建共享内存时(尚未有任何地址映射)共享内存的情况 */
        ------ Shared Memory Segments --------
    key        shmid    owner    perms    bytes    nattch    status      
        0x00000000 753665   david    666      2048      0                       

            Child: Attach shared-memory: 0xb7f59000 /* 共享内存的映射地址 */
        Parent: Attach shared-memory: 0xb7f59000
        /* 在父子进程中进行共享内存的地址映射后共享内存的情况 */
        ------ Shared Memory Segments --------
    key        shmid    owner    perms    bytes    nattch    status      
        0x00000000 753665   david    666      2048      2                       

            Child: Wait for enable data...

            Input some string:
        Hello /* 用户输入字符串“Hello” */
        Parent: Deattach shared-memory
        /* 在父进程中解除共享内存的映射关系后共享内存的情况 */
        ------ Shared Memory Segments --------
    key        shmid    owner    perms    bytes    nattch    status      
        0x00000000 753665   david    666      2048      1                       
        /* 在子进程中读取共享内存的有效数据并打印 */
        Child: Shared-memory :hello

            Child: Deattach shared-memory
        /* 在子进程中解除共享内存的映射关系后共享内存的情况 */
        ------ Shared Memory Segments --------
    key        shmid    owner    perms    bytes    nattch    status      
        0x00000000 753665   david    666      2048      0                       

            Delete shared-memory
        /* 在删除共享内存后共享内存的情况 */
        ------ Shared Memory Segments --------
    key        shmid    owner    perms    bytes    nattch    status      

            Finished     
    本文选自华清远见嵌入式培训教材《从实践中学嵌入式Linux应用程序开发》
此帖出自信息发布论坛
点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表