共享内存

共享内存

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

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

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

  • 创建共享内存

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\n", shmid);
    }
    system("ipcs -m");

    if((shmaddr = shmat(shmid, 0, 0)) < (char *)0){
        perror("shmat");
        exit(1);
    }else{
        printf("attached shared-memory\n");
    }
    system("ipcs -m");

    if(shmdt(shmaddr) < 0){
        perror("shmdt");
        exit(1);
    }else{
        printf("detached shared-memory\n");
    }
    system("ipcs -m");

    if(shmctl(shmid, IPC_RMID, NULL) < 0){
        perror("shmctl");
        exit(1);
    }else{
        printf("delete shared-memory\n");
    }
    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\n";

    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\n", 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

转载于:https://www.cnblogs.com/fuluwwa/p/6781612.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值