进程间通信之共享内存

何为共享内存

共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

但要特别注意的是共享内存并未提供同步机制。也就是说,在第一个进程结束对共享内存的操作之前,并没有自动机制可以阻止第二个进程开始对它进行读取。所以通常需要使用其它的机制来同步对共享内存的访问,比如信号量。

共享内存机制

              

如图,再物理地址空间中开辟一块空间作为共享内存,然后PCB1和PCB2通过页表+MMU的机制将这块物理地址空间挂接到各自的虚拟地址空间,如此,就可以使这两个进程通过地址空间看到同一份公共资源:共享内存。原理就是如此简单,但底层实现还是很复杂的。

需要特别说明的是:

通过共享内存实现进程间通信是最快的!

为什么呢?对比其它的进程间通信机制,都是进程1将数据写到公共资源上,进程2去读,这里面就包含了两次拷贝,第一次将数据从用户空间拷贝到内核,第二次将数据从内核拷贝到用户空间。再来看共享内存机制:进程1将数据写到共享内存,然后无需任何拷贝,进程2可以直接访问到这部分数据,所以就节省了两次拷贝的时间。

函数原型

创建和获取共享内存:

         

size指定共享内存大小,最好设置为4096的整数倍,因为操作系统以页为基本单位来分配共享内存。

销毁:

         

cmd传IPC_RMID即可,buf设为NULL,不关心。

挂接与去挂接:

         

shmaddr可以设为你想映射的虚拟地址,但一般不自己指定,因为你不知道哪里合适,所以设为NULL即可。shmflg缺省为0.

举个栗子

server不断往共享内存中写数据,client来读。(同步问题暂未考虑)

comm.h

#pragma once

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

#define _PATH_NAME_ "/tmp"
#define _PROJ_ID_ 0x666

int create_shm(int size);
int get_shm();
int destroy_shm(int shm_id);
void * at(int shm_id);
int dt(void *addr);

comm.c

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

static int comm_shm(int size, int flag)
{
	key_t key = ftok(_PATH_NAME_, _PROJ_ID_);
	if (key < 0)
	{
		perror("ftok");
		return -2;
	}

	return shmget(key, size, flag);
}

int create_shm(int size)
{
	int flag = IPC_CREAT | IPC_EXCL | 0644;
	return comm_shm(size, flag);
}


int get_shm()
{
	int flag = IPC_CREAT;
	return comm_shm(0, flag);	
}

int destroy_shm(int shm_id)
{
	return shmctl(shm_id, IPC_RMID, NULL);
}

void * at(int shm_id)
{
	return shmat(shm_id, NULL, 0);
}

int dt(void *addr)
{
	return shmdt(addr); 
}

server.c

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


int main()
{
	int shm_id = create_shm(4096);
	char *addr = (char *)at(shm_id);

	int i = 0;
	while (1)
	{
		addr[i] = 'A';
		addr[i + 1] = 0;
		++i;
		i %= 4096;
		sleep(1);
	}

	dt(addr);
	destroy_shm(shm_id);

	return 0;
}

client.c

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


int main()
{
	int shm_id = get_shm();
	char *addr = (char *)at(shm_id);

	int i = 0;
	while (1)
	{
		printf("%s\n", addr);
		sleep(1);
	}

	dt(addr);

	return 0;
}

运行结果:

         

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fireplusplus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值