进程间通信——共享内存

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程地址空间,这些进程间数据传递将不在涉及到内核,但任何事都有二义性,它是一个临界资源,但这样的方法却没有给提供任何保护。


如图:


 将共享区的代码通过页表映射到不同的PCB下,就可以实现共享内存,


以下为系统调用:

int shmget(key_t key,size_t size,int shflg);  //创建共享内存
void* shmat(int shmid,const char* shmaddr,int shmflg);  //映射关系

参数:

        shmid:共享内存标识符

        shmaddr:指定要连接的地址,为NULL时,自动选择一个地址

        shmflg:设置共享内存特性,一般为0

返回值:成功返回一个指向共享内存的指针,失败返回-1

int shmdt(const char* shmaddr);  //断开映射关系
int shmctl(int shmid,int cmd,struct shmid_da* buf);  //控制共享内存

以下是代码实现:

comm.h

#pragma once

#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>

#define PATHNAME "."
#define PROJ_ID 0x6666

int createShm(int size);

int destoryShm(int shmid);

int getShm(int size);

comm.c

#include<stdio.h>
#include"comm.h"

static int commShm(int size,int flags)
{
    key_t k = ftok(PATHNAME,PROJ_ID);
    if (k<0)
    {
        perror("ftok");
        return -1;
    }
    int shmid = 0;
    if((shmid = shmget(k,size,flags)) < 0)
    {
        perror("shmget");
        return -2;
    }
    return shmid;
}

int destoryShm(int shmid)
{
    if(shmctl(shmid,IPC_RMID,NULL) < 0)
    {
        perror("shmctl");
        return -1;
    }
    return 0;
}

int createShm(int size)
{
    return commShm(size,IPC_CREAT|IPC_EXCL|0666);
}

int getShm(int size)
{
    return commShm(size,IPC_CREAT);
}

server.c

#include<stdio.h>
#include"comm.h"

int main()
{
    int shmid = createShm(4096);
    char *addr = shmat(shmid,NULL,0);
    sleep(2);
    int i = 0;
    while(i++ < 26)
    {
        printf("Client# %s\n",addr);
        sleep(1);
    }
    shmdt(addr);
    sleep(2);
    destoryShm(shmid);
    return 0;
}

client.c

#include<stdio.h>
#include"comm.h"

int main()
{
    int shmid = getShm(4096);
    sleep(1);
    char* addr = shmat(shmid,NULL,0);
    sleep(2);
    int i = 0;
    while(i < 26)
    {
        addr[i] = 'A' +i;
        i++;
        addr[i] = 0;
        sleep(1);
    }
    shmdt(addr);
    sleep(2);

    return 0;
}

结果可以自己实验一下,但是和消息队列一样,它的生命周期也是随内核,故需要用

ipcs -m //查看
ipcrm -m//删除 IPC资源


猜你喜欢

转载自blog.csdn.net/duckyloser/article/details/79947983