进程间通信之共享内存

我们知道进程间同行的实质是让两个进程看到同一份资源。共享内存正是让两个进程看到同一份资源的方法之一。那么两个进程怎么共享一个内存呢?
我们都知道,每个进程都有自己的进程空间,进程的虚拟地址空间通过页表映射到物理内存上,而不同的进程的虚拟地址空间是相互独立的,也就不可能出现两个进程的虚拟地址空间橡胶的情况。但是,不同的进程虚拟地址空间都要映射到物理内存中,因此如果两个进程空间映射到同一块物理内存,那么这两个进程将看到相同的内容,而这块物理内存就是两个进程的临界资源了。
我们可以用这样的模型来看待这个过程:
这里写图片描述
共享内存实现进程间通信的机制就是这样的。
有关函数:
创建共享内存:
int shmget(key_t key, size_t size, int shmflg);
key:共享内存段名字。
size:共享内存大小。
shmflg:权限标志。
返回值:成功返回共享内存段的标识码,失败返回-1。

将共享内存段连接到进程地址空间:
void shmat(int shmid, const void *shmaddr, int shmflg);
shmid:共享内存标识符。
shmaddr:指定连接的地址。
shmaddr为NULL,核⼼心⾃自动选择⼀一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会⾃自动向下调整为SHMLBA的整数倍。公式:s hmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表⽰示连接操作⽤用来只读共享内存
shmflg:两个可能取值为SHM_RND和SHM_RDONLY。
返回值:成功返回共享内存指针,失败返回-1。

将共享段与当前进程脱离:
int shmdt(const void *shmaddr);
shmaddr由shmat返回的指针。
返回值:成功返回0,失败返回-1。

控制共享内存:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:由shmget返回的共享内存标识码。
cmd:将要采取的动作(有三个选择值,删除用IPC_RMID)。
这里写图片描述
buf:指向一个保存着共享内存的模式状态和权限的数据结构(一般可赋为NULL)。

可以看到,共享内存实现进程间通信,是两个进程直接与内存的数据交换,不涉及内核,因此少了中间数据进出内核的开销,因此共享内存是速度最快的进程间通信方式,也因此共享内存必须进行显式地释放,它的生命周期是随内核的。而因为共享内存没有同步互斥,所以在使用共享内存时最好加上信号量来解决同步问题,当然这篇文章不涉及信号量问题。

实现进程间简单通信:
Makefile文件:

.PHONY : all
all : server client

server : server.c comm.c
    gcc -o server server.c comm.c

client : client.c comm.c
    gcc -o client client.c comm.c

.PHONY : clean
clean :
    rm -f server client

comm.c文件:

#include "comm.h"

static int _GetCommShm(int size, int flag)
{
    key_t key = ftok(PATHNAME, PROJ_ID);
    if(key < 0)
    {
        printf("ftok\n");
        return -1;
    }

    int shmid = shmget(key, size, flag);
    if(shmid < 0)
        printf("shmget\n");
    return shmid;
}

int CreatShm(int size)
{
    return _GetCommShm(size, IPC_CREAT|IPC_EXCL|0666);  
}

int GetShm(int size)
{
    return _GetCommShm(size, IPC_CREAT);    
}

int DelShm(int shmid)
{
    return shmctl(shmid, IPC_RMID, NULL);
}

server.c文件:

#include "comm.h"

int main()
{
    int shmid = CreatShm(4096);
    if(shmid < 0)
    {
        printf("CreatShm\n");
        exit(EXIT_FAILURE);
    }
    char *addr = shmat(shmid, NULL, 0);
    int i = 0;
    while(i++ < 20)
    {
        printf("%s%d\n", addr, i);
        sleep(1);
    }
    sleep(2);
    shmdt(addr);
    DelShm(shmid);

    return 0;
}

clean.c文件:

#include "comm.h"

int main()
{
    int shmid = GetShm(4096);
    if(shmid < 0)
    {
        printf("GetShm\n");
        exit(EXIT_FAILURE);
    }
    char *addr = shmat(shmid, NULL, 0);
    int i = 0;
    while(i < 20)
    {
        printf("%d\n", i);
        addr[i] = 'A';
        i++;
        addr[i] = 0;
        sleep(1);
    }
    shmdt(addr);

    return 0;
}

代码功能是client端向共享内存中放入逐渐变长的由A组成的字符串,server端从共享内存中取出并打印到屏幕上,运行结果图:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值