进程间通信之共享内存

共享内存

  • 一. 什么是共享内存
  • 二. 共享内存有关函数
    • 1.获取key
    • 2.打开创建共享内存对象 - shmget
    • 3.映射空间地址 - shmat
    • 4.取消映射 - shmdt
    • 5.删除共享内存对象 - shmctl
  • 三. 实例
  • 四. 注意事项
    • 1.查看当前系统的共享内存
    • 2.当两个进程间ftok参数不一样时,shmid也不一样,共享内存不是同一个空间
    • 3.释放共享内存

一. 什么是共享内存

共享内存就是允许两个或多个进程共享一片存储区,是操作系统在实际物理内存开辟一块空间,当一个进程往该空间写入内容时,另外一进程会访问该空间,得到写入的值,即实现了进程间的通信。
共享内存做到数据不需要在客户机和服务器端之间来回复制,数据直接写到内存中,不需要多次数据拷贝,是进程间最有效的方式
进程间通信之共享内存_第1张图片

二. 共享内存有关函数

1.获取key

功能 : 获取一个独一无二的key,作为传给共享内存的一个参数

#include 
#include 

key_t ftok(const char *pathname, int proj_id);
key_t key = ftok("./read", 'a');
pathname:
		提前创建的可访问文件的文件名,可以随意写
proj_id:
		任意一个字符

返回值:
		成功则返回生成的key值,失败则返回-1

2.打开创建共享内存对象 - shmget

功能:创建/打开一个共享内存对象

#include 
#include 

//在内核上创建共享内存
int shemid = shmget(key, 1024, IPC_CREAT | 0666);
int shmget(key_t key, size_t size, int shmflg);

key:
		表示要打开或者创建一个对象的“密钥”
		可以写0或者IPC_PRIVATE:表示共享内存对象是私有的
size:
		要创建的共享内存大小
shmflg:
		打开或者创建时的权限
		IPC_CREAT:不存在则创建
		IPC_EXCL:存在(如果加上了IPC_CREAT)就报错
		0666
返回值:
		成功返回ID号,失败返回-1

3.映射空间地址 - shmat

功能:把内核中的共享内存空间映射到用户空间

#include 
#include 

void *shmat(int shmid, const void *shmaddr, int shmflg);
char *shmaddr = shmat(shmid, NULL, 0);
void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid:
		共享内存的id号
shmaddr:
		可以指定要映射的空间地址
		NULL:表示系统决定
		0x...:表示指定要把内核空间映射到这个地址
shmflg:
		表示共享内存的操作权限(读写)
		SHM_RDONLY:表示只读(不用)
		0:可读可写
返回值:
		成功返回映射后的用户空间地址,失败返回(void *)-1

4.取消映射 - shmdt

功能:把shmat映射后的空间取消掉,释放进程地址空间

#include 
#include 

int shmdt(const void *shmaddr);
shmaddr:
		shmat返回的地址(映射地址)
返回值:
		成功返回0,失败返回-1

5.删除共享内存对象 - shmctl

功能:整体控制共享内存对象

#include 
#include 

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

shmctl(shmid, IPC_RMID, NULL);
shmid:
		共享内存对象ID号
cmd:
		要执行的操作
		IPC_STAT  (获取对象属性)
    	IPC_SET (设置对象属性)
    	IPC_RMID (删除对象)
buf:
		用于设置或者获取对象的属性,如果是删除对象,写NULL
返回值:
		成功返回0,失败返回-1

注:删除对象并不是直接删除,而是标记这个对象为删除状态

三. 实例

write.c依次往共享内存中输入字符a-z, read.c读取共享内存中的数据,并打印出来
write.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main()
{
    key_t key = ftok("./read", 'a');
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }

    // 创建共享内存
    int shmid = shmget(key, 1024*4, IPC_CREAT | 0666);
    if(shmid < 0)
    {
        perror("shmget");
        return -1;
    }

    // 映射空间地址
    char *shmaddr = shmat(shmid, NULL, 0);
    if(shmaddr == (void *)-1)
    {
        perror("shmat");
        return -1;
    }

    char c='a';
    for( ; c <= 'z'; c++)
    {
        printf("%c\n",c);
        shmaddr[c-'a']=c;
        sleep(1);
    }
    shmdt(shmaddr);
    shmctl(shmid, IPC_RMID, NULL);
}

read.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main()
{
    key_t key = ftok("./read", 'a');
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }

    //在内核上创建共享内存
    int shmid = shmget(key, 1024*4,IPC_CREAT|0666);
    if(shmid < 0)
    {
        perror("shmget");
        return -1;
    }

    //映射空间地址
    char *shmaddr = shmat(shmid, NULL, 0);
    if(shmaddr == (void *)-1)
    {
        perror("shmat");
        return -1;
    }

    int i = 20;
    while(i)
    {	
        printf("result : %s\n", shmaddr);
        sleep(1);
        i--;
    }
    shmdt(shmaddr);
    shmctl(shmid, IPC_RMID, NULL);

}

进程间通信之共享内存_第2张图片

注意 : 当运行程序时,先运行read.c,程序启动就直接读取共享内存中的数据,此时并没有往共享内存中写入数据,
但是read.c并没有阻塞

四. 注意事项

1.查看当前系统的共享内存

	ipcs -m    			//查看当前系统的共享内存
	ipcs -m shmid       //删除某个共享内存

进程间通信之共享内存_第3张图片

2.当两个进程间ftok参数不一样时,shmid也不一样,共享内存不是同一个空间

write.c
进程间通信之共享内存_第4张图片

read.c
在这里插入图片描述
在这里插入图片描述

3.释放共享内存

当我结束两个进程时,如果代码中没有shmctl,那么共享内存还会一直存在,会造成内存泄漏,所以当我们使用shmget创建共享内存后,如果不在使用该共享内存,应当即时释放

你可能感兴趣的:(进程间通信,共享内存)