共享内存实现

进程间通信方式

  • 无名管道(pipe):用于具有父子关系的进程之间的通信
  • 有名管道(fifo):可用于非父子关系之间的进程
  • 信号量(semaphore):是一个计数器,可用于进程或线程的同步或互斥,常用作锁机制
  • 消息队列(message):是消息的链表,允许进程将格式化的数据流以消息队列形式发送给任意进程
  • 共享内存(shared memory):映射一段能够被其他进程所访问的内存,由一个进程创建,多个进程访问,是最快的IPC方式,不需要进行频繁的用户态内核态切换。但需要与其他机制,如信号量配合来实现进程间的同步

区别

管道,消息队列需要在内核和用户空间进行四次内存拷贝,共享内存只需要拷贝两次。一次是输入文件到共享内存区,另一次是从共此昂内存区到输出文件。

共享内存实现机制

  • POSIX 共享内存
  • XSI共享内存
  • mmap 共享内存

不同进程共享内存:同一块物理内存被映射到多个进程的进程地址空间。当前进程可以看到其他进程对于 shared memory数据的更新。但由于不同进程访问同一块空间,需要进行同步或互斥,一般使用互斥锁或信号量。

特点

  • 效率高,进程直接读写内存,不需要进行频繁的用户状态切换,就保证了不需要频繁地进行数据拷贝。
  • 不同进程之间共享和传递数据的最有效方式
  • 共享的内存安排为同一段物理内存

XSI实现机制

#include 
#include 
#include 

/*
@brief:1、创建共享内存
@param:
	key:类似于文件名,是系统全局唯一的,方便其他进程使用同样的key打开同样一段共享内存,通过使用ftok()函数使用pathname和PROJ_ID产生。即约定一个文件名和一个项目的PROJ_ID来在同一个系统中确定一段共享内存的key
		ftok()并不会创建文件,必须指定一个存在的文件名,它实际上使用的是指定文件的inode编号和文件所在设备的设备编号
		也可以直接写IPC_PRIVATE,内核会在不产生冲突的共享内存段id的前提下新建一段共享内存,此时一定是新创建,shmflg=IPC_CREAT
	size:共享内存大小
	shmflg:创建标志
		IPC_CREAT:
		IPC_EXCL:
		0:访问一个已存在的共享内存
		SHM_HUGETLB:申请大页内存,提高内存对内存管理的处理效率
		SHM_HUGE_2MB
@return:
	shmid:类似于文件描述符,fork产生的子进程,可以直接使用shmid来使用相关共享内存
*/
int shmget(key_t key, size_t size, int shmflg);

/*
@brief:将共享内存映射到当前进程的内存空间,映射之后,通过访问进程的虚拟地址就可以访问到共享内存段了
@param:
	shmid:上述创建的返回id值
	shmaddr:指定共享内存映射到当前进程中的地址,此时shmflg=SHM_RND,大多数情况下应该置NULL,此时系统会自己选择地址
	shmflg:
@return:
	调用成功则返回映射地址,失败为-1
*/
void *shmat(int shmid, const void* shmaddr, int shmflg);

/*
@brief:解除映射,只能解除,不能删除
@param:
	shmaddr:要解除的地址空间
*/
int shmdt(const void *shmaddr);

/*
@brief:控制共享内存
@param:
	shmid:
	cmd:对共享内存进行的操作
		IPC_STAT:得到共享内存的状态
		IPC_SET:设置共享内存的状态
		IPC_RMID:删除共享内存
	buf:
		struct shmid_ds {
			struct ipc_perm	 shm_perm;		// 所有者与权限
			size_t			shm_segsz;		// 共享内存段的大小		
			time_t			shm_atime;		// last attach time
			time_t			shm_dtime;		// last detach time
			time_t			shm_ctime;		// last change time
			pid_t			shm_cpid;		// pid of creator
			pid_t			shm_lpid;		// pid of last shmat/shmdt
			shmatt_t		shm_nattch;		// number of current attaches
		}
		struct ipc_perm {
			key_t	__key;		// shmget中的key
			uid_t	uid;		// 所有者的用户id
			gid_t	gid;		// 所有者的组id
			uid_t	cuid;		// 创建者的用户id
			gid_t	cgid;		// 创建者的组id
			unsigned short mode; // 
		}
*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

mmap实现机制

mmap是能够实现内存的映射,它能够将一个文件映射到内存中,在程序中就可以直接使用虚拟内存地址对文件内容进行访问,让程序对文件访问更方便。

mmap系统调用可以用在很多场合,并不仅局限于实现共享内存。

实现在父子进程之间共享内存。

#include 

/*
	@brief:映射虚拟地址为虚拟内存
	@param:
		flags:
			MAP_SHARED:申请一段共享内存,可以映射到具体文件,也可以不,fd=-1
*/
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

// 解除映射
int munmap(void *addr, size_t length);

POSIX实现机制

本质上也是mmap对文件的映射,映射的是tmpfs文件系统上的文件。

其可以将共享内存当做一个文件,这样符合Linux一切皆文件的宗旨,这样可以使用I/O复用等相关使用文件描述符的功能。当OXI共享内存其得到的共享内存是类文件,并不是真正的文件,所得到的shmid也只是类文件描述符,不能向平常的文件描述符那样使用。

#include 
#include 
#include 

/*
	@brief:创建或访问已创建的共享内存,实际上为open的封装,实际上POSIX共享的是/dev/shm目录中的一个tmpfs格式的文件
*/
shm_open(const char *name, int oflag, mode_t mode);

/*
	@brief:解除映射,实际上为unlink的封装
*/
shm_unlink(const char* name);

你可能感兴趣的:(操作系统)