跳到主要内容

Linux 共享内存(mmap)

mmap 函数是 Linux系统中的一个系统调用,用于将一个文件或设备映射到进程的虚拟地址空间,从而使得进程可以通过访问内存来读写文件或设备数据,这种技术称为内存映射(memory mapping)。

mmap 函数原型

mmap 函数的原型如下:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

各参数的含义如下:

  • addr:指定映射区域的首地址,通常设置为 0 表示由系统自动选择。
  • length:指定映射区域的长度。
  • prot:指定映射区域的保护方式,可以是以下值的按位或:
    • PROT_READ:允许读取映射区域。
    • PROT_WRITE:允许写入映射区域。
    • PROT_EXEC:允许执行映射区域。
  • flags:指定映射区域的标志,可以是以下值的按位或:
    • MAP_SHARED:共享映射,多个进程可以同时访问同一映射区域。
    • MAP_PRIVATE:私有映射,只有当前进程可以访问映射区域。
    • MAP_ANONYMOUS:创建匿名映射,不需要指定文件描述符。
    • MAP_FIXED:指定映射区域的地址,如果该地址已被占用则会失败。
  • fd:指定要映射的文件描述符,如果是创建匿名映射则设置为 -1。
  • offset:指定文件中的偏移量,对于匿名映射应该设置为 0。

返回值:成功返回映射区域的起始地址,失败则返回 MAP_FAILED(-1)。

mmap 共享内存示例程序

下面是一个使用 mmap 函数创建共享内存的示例程序。

GitHub:shared_memory_mmap.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define MEM_SIZE 64
#define TEST_MSG "Hello, GetIoT.tech!"

int main()
{
int fd;
char *data;
const char *filename = "/tmp/shared_memory";

/* 创建一个文件,用于共享内存 */
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd < 0) {
perror("open");
exit(1);
}
/* 设置文件大小 */
if (ftruncate(fd, MEM_SIZE) < 0) {
perror("ftruncate");
exit(1);
}
/* 映射到内存中 */
data = (char *) mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
perror("mmap");
exit(1);
}
/* 关闭文件描述符,不再需要 */
close(fd);

/* 使用共享内存 */
memcpy(data, TEST_MSG, sizeof(TEST_MSG));
printf("%s\n", (char *)data);

/* 解除映射 */
if (munmap(data, MEM_SIZE) < 0) {
perror("munmap");
exit(1);
}

/* 删除文件 */
if (unlink(filename) < 0) {
perror("unlink");
exit(1);
}

return 0;
}

编译代码:

gcc shared_memory_mmap.c -o shared_memory_mmap

执行结果:

$ ./shared_memory_mmap 
Hello, GetIoT.tech!

mmap 和 shmget 的区别

Linux 系统中,shmget 和 mmap 接口都可以用来创建共享内存。

shmget 函数创建的共享内存是由操作系统内核进行管理,它是一块共享的物理内存,不会占用进程的虚拟地址空间。在使用 shmget 创建的共享内存时,需要调用 shmat 函数将共享内存映射到进程的虚拟地址空间中。shmget 适用于进程间需要共享数据,但数据量较大的情况。

mmap 函数创建的共享内存则是通过文件系统实现的,它将文件映射到进程的虚拟地址空间中,可以被所有映射它的进程共享。mmap 适用于进程间需要共享小量数据或者一些状态信息的情况。

总体来说,两种方式都可以用于实现进程间的共享内存,不同的是它们的使用场景略有不同。shmget 适用于大数据量的共享,mmap 适用于小数据量的共享。此外,由于 mmap 的实现方式,mmap 所创建的共享内存可以被多个进程在不同的机器上共享,而 shmget 只能在同一台机器上的进程之间共享。