• 共享内存


    共享内存

    共享内存是一种最为高效的进程间通信方式,进程可以直接读写共享内存而不需要数据的拷贝。

    内核专门留出了一块内存区,这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。

    由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。

    • 创建共享内存

    SYNOPSIS

    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    int shmget(key_t key, size_t size, int shmflg);
    

    key: IPC_PRIVATE - 会建立新共享内存对象
    size: 共享内存大小
    shmflg: 权限位
    return - 共享内存段标识符

    • 映射共享内存

    把创建的共享内存映射到具体的进程空间去。

    SYNOPSIS

    void *shmat(int shmid, const void *shmaddr, int shmflg);
    

    shmid: 要映射的共享内存标识符
    shmaddr: 映射的地址
    shmflg: SHM_RDONLY: 共享内存只读; 0: 可读写
    return - 被映射的段地址

    • 撤销共享内存

    SYNOPSIS

    int shmdt(const void *shmaddr);
    

    shmaddr: 被映射的共享内存地址

    • 共享内存的控制

    SYNOPSIS

       #include <sys/ipc.h>
       #include <sys/shm.h>
    
       int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    

    shmid: 共享内存标识符
    cmd:
    IPC_STAT - 得到共享内存的状态。把共享内存的shmid_ds结构复制到buf中。
    IPC_SET - 改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内。
    IPC_RMID - 删除这片共享内存
    buf: shmid_ds结构体。

    struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Last change time */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
    };
    

    实例1:

    这里要介绍的一个命令是 ipcs,这是用于报告进程间通信机制状态的命令。它可以查看共享内存、消息队列等各种进程间通信机制的情况。
    也可通过shell执行ipcrm -m shmid来删除共享内存。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    #define BUFSIZE 2048
    
    int main()
    {
    	int shmid;
    	char *shmaddr;
    
    	if((shmid = shmget(IPC_PRIVATE, BUFSIZE, 0666)) < 0){
    		perror("shmget");
    		exit(1);
    	}else{
    		printf("created shared-memory: %d
    ", shmid);
    	}
    	system("ipcs -m");
    
    	if((shmaddr = shmat(shmid, 0, 0)) < (char *)0){
    		perror("shmat");
    		exit(1);
    	}else{
    		printf("attached shared-memory
    ");
    	}
    	system("ipcs -m");
    
    	if(shmdt(shmaddr) < 0){
    		perror("shmdt");
    		exit(1);
    	}else{
    		printf("detached shared-memory
    ");
    	}
    	system("ipcs -m");
    
    	if(shmctl(shmid, IPC_RMID, NULL) < 0){
    		perror("shmctl");
    		exit(1);
    	}else{
    		printf("delete shared-memory
    ");
    	}
    	system("ipcs -m");
    
    	exit(0);
    }
    

    结果如下:

    xxx@xxx-pc:~/Documents$ ./a.out 
    created shared-memory: 2162702
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 2162702    xxx        666        2048       0                       
    
    attached shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 2162702    xxx        666        2048       1                       
    
    detached shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status      
    0x00000000 2162702    xxx        666        2048       0                       
    
    delete shared-memory
    
    ------ Shared Memory Segments --------
    key        shmid      owner      perms      bytes      nattch     status
    

    ftok()函数

    系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

    SYNOPSIS

       #include <sys/types.h>
       #include <sys/ipc.h>
    
       key_t ftok(const char *pathname, int proj_id);
    

    proj_id: 取值(1~255)

    在一般的UNIX实现中,是将文件的索引节点号取出(通过ls -i),前面加上子序号(proj_id)得到key_t的返回值。
    如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。

    如果要确保key_t值不变,要么确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值。

    实例2:

    实现一进程写共享内存,一进程读共享内存并且读好之后释放共享内存空间。

    写进程p2:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <string.h>
    
    #define BUFSIZE 2048
    
    int main()
    {
    	int shmid;
    	char *shmaddr;
    	key_t key;
    	char *str = "shmat, shmdt - System V shared memory operations
    ";
    
    	if((key = ftok("/tmp", 0x03)) < 0){
    		perror("ftok error");
    		exit(1);
    	}
    
    	if((shmid = shmget(key, BUFSIZE, IPC_CREAT|IPC_EXCL|0666)) < 0){
    		perror("shmget");
    		exit(1);
    	}
    
    	if((shmaddr = shmat(shmid, 0, 0)) < (char *)0){
    		perror("shmat");
    		exit(1);
    	}
    	
    	memcpy(shmaddr, str, strlen(str));
    
    	if(shmdt(shmaddr) < 0){
    		perror("shmdt");
    		exit(1);
    	}
    /*
    	if(shmctl(shmid, IPC_RMID, NULL) < 0){
    		perror("shmctl");
    		exit(1);
    	}
    */
    
    	exit(0);
    }
    

    读进程p1:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    int main()
    {
    	int shmid;
    	char *shmaddr;
    	key_t key;
    
    	if((key = ftok("/tmp", 0x03)) < 0){
    		perror("ftok error");
    		exit(1);
    	}
            
                /* get shared-memory according to key */
    	if((shmid = shmget(key, 0, 0)) < 0){
    		perror("shmget");
    		exit(1);
    	}
    
    	if((shmaddr = shmat(shmid, 0, 0)) < (char *)0){
    		perror("shmat");
    		exit(1);
    	}
    
    	printf("%s
    ", shmaddr);
    
    	if(shmdt(shmaddr) < 0){
    		perror("shmdt");
    		exit(1);
    	}
    
    	if(shmctl(shmid, IPC_RMID, NULL) < 0){
    		perror("shmctl");
    		exit(1);
    	}
    
    	exit(0);
    }
    

    结果如下:

    xxx@xxx-pc:~/Documents$ ./p2
    xxx@xxx-pc:~/Documents$ ipcs -m
    
    ------ Shared Memory Segments --------
    0x03080001 2359308    xxx        666        2048       0                       
    
    xxx@xxx-pc:~/Documents$ ./p1
    shmat, shmdt - System V shared memory operations
    

    如果先运行./p1,共享内存不存在,报错:

    xxx@xxx-pc:~/Documents$ ./p1
    shmget: No such file or directory
    

    如果重复运行./p2,此时共享内存已存在,加了IPC_EXCL标志,会报错:

    xxx@xxx-pc:~/Documents$ ./p2
    xxx@xxx-pc:~/Documents$ ./p2
    shmget: File exists
  • 相关阅读:
    我的插件框架·前传
    在OpenSUSE中听歌
    ASP.NET MVC 3.0 源码阅读手记(1)
    Mono on Linux 开发与实践札记(1)
    探讨对Web控件的异常处理
    进销存管理中负库存产生的原因以及对应措施
    看了一篇不错的文章 使用 UTF8 对 XML 文档进行编码
    进销存管理中对红冲处理的误区
    Ajax学习笔记(2) 一定要用XML吗?
    打造自己的Html文本编辑控件
  • 原文地址:https://www.cnblogs.com/fuluwwa/p/6781612.html
Copyright © 2020-2023  润新知