Android C++系列:Linux进程间通信(二)

335 阅读3分钟

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战」。

内存映射

mmap/munmap

mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length);

image-20211120085339182.png

如果addr参数为NULL,内核会自己在进程地址空间中选择合适的地址建立映射。如果 addr不是NULL,则给内核一个提示,应该从什么地址开始映射,内核会选择addr之上的某个 合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。len参数是需 要映射的那一部分文件的长度。off参数是从文件的什么位置开始映射,必须是页大小的整 数倍(在32位体系统结构上通常是4K)。filedes是代表该文件的描述符。

prot参数有四种取值:

  • PROT_EXEC表示映射的这一段可执行,例如映射共享库
  • PROT_READ表示映射的这一段可读
  • PROT_WRITE表示映射的这一段可写
  • PROT_NONE表示映射的这一段不可访问

flag参数有很多种取值,这里只讲两种,其它取值可查看mmap(2)

  • MAP_SHARED多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修 改,另一个进程也会看到这种变化。
  • MAP_PRIVATE多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修 改,另一个进程并不会看到这种变化,也不会真的写到文件中去。

如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程 的映射内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。

下面做一个简单的实验。

qingkouwei@ubuntu:~$ vi hello 
qingkouwei@ubuntu:~$ cat hello
helloworld
qingkouwei@ubuntu:~$ od -tx1 -tc hello
0000000 68 65 6c 6c 6f 77 6f 72 6c 64 0a
0000013

使用mmap映射

#include <stdlib.h> 
#include <sys/mman.h> 
#include <fcntl.h>
int main(void){
	int *p;
	int fd = open("hello", O_RDWR); 
	if (fd < 0) {
		perror("open hello");
		exit(1); 
	}
	p = mmap(NULL, 6, PROT_WRITE, MAP_SHARED, fd, 0); 
	if (p == MAP_FAILED) {
		perror("mmap");
		exit(1); 
	}
	close(fd);
	p[0] = 0x30313233; 
	munmap(p, 6); 
	return 0;
}
  • 用于进程间通信时,一般设计成结构体,来传输通信的数据
  • 进程间通信的文件,应该设计成临时文件
  • 当报总线错误时,优先查看共享文件是否有存储空间

Unix Domain Socket

可以利用socket实现进程通信。

总结

本文介绍了mmap函数:mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存 地址,对文件的读写可以直接用指针来做而不需要read/write函数。