进程间通信-共享内存

来源:互联网 发布:浪漫的c语言小程序 编辑:程序博客网 时间:2024/06/17 09:57

前言


共享内存允许两个进程或多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,这是最快的一种IPC。

使用共享存储要掌握的唯一窍门是,在多个进程之间同步访问一个给定的存储区。若服务器进程正在将数据放入共享存储区,则在它做完这一操作之前,客户进程不应当去取这些数据通常,信号量用于同步共享存储访问。(也可以用记录锁或者互斥量),
也就是说,我们需要确保一个进程在写的时候,另外一个进程不能去读,所以我们可以使用信号量进行共享内存访问。
如图所示,两个进程使用共享内存实现通信时。
这里写图片描述

这里写图片描述

创建共享内存

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

注意:
参数size是该共享存储的段长度,以字节为单位。实现通常将其向上取整为系统页(4K)长的整倍数,若应用指定的size并非系统页长的整数倍,那么最后最后一页剩下的部分是不可使用的。
如果正在引用一个现存的段时,则将size指定为0,当创建一个新段时,段内的内容初始化为0.
key标示用:

key_t ftok(const char* pathname, int prj_id);

挂接共享内存

void* shmat(int shmid, const void* addr,int flag);  //返回值:若成功,返回指向共享存储段的指针;若出错,返回-1

flag一般表示什么方式进行挂接,一般都是取0,
shmid是挂接的进程号。
这个函数返回的是一个地址,我们可以想一下使用malloc的时候如何使用的,这个和那个类似。

去关联共享内存

当对共享存储段的操作已经结束了,则调用shmdt与该段分离,注意,这并不从系统中删除其标识符以及相关的数据结构该标识符仍然存在,直至某个进程(一般是服务器进程)带IPC_RMID命令调用shmctl特定地删除它为止。

int shmdt(const void*shm addr);

我么可以类比malloc 和free 来学习shmat和shmdt.

销毁共享内存

int shmctl(int shmid,int cmd,struct shmid_dfs*buf);

我们可以用它来删除共享内存,当cmd取IPC_RMID的时候就可以删除共享内存,另外我们也可以使用命令来进行操作ipcrm -m xxx
这样也可以进行销毁共享内存。

实例

common.h

#ifndef __COMM_H_#define __COMM_H_#include<stdio.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#define PATHNAME "."#define PROJID 0x6666#define SIZE 4096*1int Comm_Shm(int flags);int Create_Shm();int Get_Shm();int Destroy(int shmid);char* At_Shm(int shmid);int Dt_Shm(char* mem_addr);#endif

common.c

#include"common.h"int Comm_Shm(int flags){    key_t shmkey=ftok(PATHNAME,PROJID);    if(shmkey<0)    {        perror("ftok");        return -1;    }    int shmid=shmget(shmkey,SIZE,flags);    if(shmid<0)    {        perror("shmget");        return -2;    }    return shmid;}int Create_Shm(){    return Comm_Shm(IPC_CREAT|IPC_EXCL|0666);}int Get_Shm(){    return Comm_Shm(0);}int Destroy(int shmid){    int ret=shmctl(shmid,IPC_RMID,NULL);    if(ret<0)    {        perror("shmctl");        return -1;    }    return ret;}char* At_Shm(int shmid){    char *shm=(char*)shmat(shmid,NULL,0);    return shm;}int Dt_Shm(char* mem_addr){    int ret=shmdt(mem_addr);    return 0;}

serve.c

#include"common.h"int main(){    int shmid=Create_Shm();    sleep(5);    char* add=At_Shm(shmid);    while(1)    {        sleep(1);        printf("%s\n",add);    }    sleep(5);    Dt_Shm(add);    Destroy_Shm(shmid);    return 0;}

client.c

#include"common.h"int main(){    int shmid=Get_Shm();    sleep(5);    char* add=At_Shm(shmid);    printf("physic address ; %s",add);    int i=0;    while(1)    {        sleep(1);        add[i++]='a';        i%=(SIZE-1);        add[i]='\0';    }    Dt_Shm(add);    return 0;}