网站建设费预付定金什么科目,游戏ui培训,哪里可以学网站建设,wordpress 删除后台菜单在Linux系统编程中#xff0c;进程之间的通信是一项重要的任务。共享存储映射#xff08;mmap#xff09;是一种高效的进程通信方式#xff0c;它允许多个进程共享同一个内存区域#xff0c;从而实现数据的共享和通信。本文将介绍共享存储映射的概念、原理、使用方法和注意… 在Linux系统编程中进程之间的通信是一项重要的任务。共享存储映射mmap是一种高效的进程通信方式它允许多个进程共享同一个内存区域从而实现数据的共享和通信。本文将介绍共享存储映射的概念、原理、使用方法和注意事项以帮助读者更好地理解和应用共享存储映射。 文章目录 1. 共享存储映射的概念2. 共享存储映射的原理3. 共享存储映射的使用方法3.1 mmap3.1.1 函数原型、参数及返回值3.1.2 注意事项3.1.3 函数示例 3.2 munmap3.2.1 函数原型、参数及返回值3.2.2 注意事项3.2.3 函数示例 4. 父子进程mmap通信4.1 具体步骤如下4.2 示例4.3 代码解释 5. 非血缘关系进程间mmap通信5.1 具体步骤如下5.2 示例5.3 代码解释 6. 结语 1. 共享存储映射的概念
共享存储映射是一种将文件或设备映射到进程的虚拟地址空间的技术。通过共享存储映射多个进程可以访问同一个物理内存区域从而实现数据的共享和通信。 共享存储映射的主要优势包括
高效性共享存储映射避免了数据的复制和传输提高了数据访问的效率。灵活性共享存储映射可以用于不同类型的数据包括文件、设备和匿名内存等。简单性共享存储映射使用简单只需要几个系统调用就可以完成映射和解除映射的操作。
2. 共享存储映射的原理
共享存储映射的原理是将一个文件或设备映射到进程的虚拟地址空间中的一段连续的内存区域。这个内存区域被称为共享内存段。多个进程可以通过访问共享内存段来实现数据的共享和通信。 共享存储映射的过程包括以下几个步骤
创建或打开一个共享内存段。将共享内存段映射到进程的虚拟地址空间中。读写共享内存段中的数据。解除共享内存段的映射。
3. 共享存储映射的使用方法
3.1 mmap
3.1.1 函数原型、参数及返回值
mmap函数的原型如下
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);参数说明
addr指定映射的起始地址通常设置为NULL让系统自动选择合适的地址。length指定映射的长度以字节为单位。prot指定映射区域的保护方式可以是以下几个值的组合 PROT_READ可读PROT_WRITE可写PROT_EXEC可执行PROT_NONE不可访问 flags指定映射区域的标志可以是以下几个值的组合 MAP_SHARED共享映射多个进程可以访问同一个映射区域MAP_PRIVATE私有映射每个进程有自己独立的映射区域MAP_FIXED映射区域必须从指定的地址开始如果指定地址已被占用则映射失败MAP_ANONYMOUS创建一个匿名映射区域不与文件关联 fd指定要映射的文件描述符如果使用MAP_ANONYMOUS标志则该参数为-1。offset指定文件的偏移量通常设置为0。
返回值
成功时返回映射区域的起始地址。失败时返回MAP_FAILED。
3.1.2 注意事项 参数的正确设置mmap函数的参数包括起始地址、映射长度、访问权限、映射方式等。需要根据具体需求正确设置这些参数以确保映射的行为符合预期。 错误处理mmap函数的返回值为映射区域的起始地址如果映射失败返回值为MAP_FAILED。在调用mmap函数后需要检查返回值是否为MAP_FAILED并根据errno的值来确定具体的错误原因并进行相应的错误处理。 内存对齐mmap函数返回的映射区域的起始地址通常是按照系统的内存页大小 4096 进行对齐的。在使用映射区域时需要确保按照正确的偏移和长度进行访问以避免访问越界或者未映射的内存。 解除映射在不再需要映射区域时应该使用munmap函数解除对映射区域的映射。解除映射后之前映射的内存区域将不再可访问对该区域的访问将导致段错误。因此需要确保解除映射的时机和范围是正确的避免出现内存泄漏或者访问非法内存的情况。 共享内存的同步如果使用mmap函数创建了一个共享内存区域使用MAP_SHARED标志需要在多个进程之间进行同步以避免竞争条件和数据不一致的问题。可以使用信号量、互斥锁等机制来实现进程间的同步。 文件映射的同步如果使用mmap函数将文件映射到内存中需要注意对内存中的数据的修改可能不会立即写入到文件中。可以使用msync函数来将修改的数据同步到文件中或者使用munmap函数解除映射时自动进行同步。 安全性使用mmap函数时需要注意安全性问题尤其是在映射文件时。需要确保对映射区域的访问是合法的避免出现潜在的安全漏洞例如通过映射区域进行非法的内存访问或者代码注入等。
3.1.3 函数示例 下面是一个使用mmap函数的例子
#include sys/mman.h
#include fcntl.h
#include stdio.h
#include unistd.hint main() {int fd;char *shared_memory;// 打开文件fd open(shared_memory, O_RDWR);if (fd -1) {perror(open);return 1;}// 将文件映射到进程的虚拟地址空间中shared_memory (char *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (shared_memory MAP_FAILED) {perror(mmap);return 1;}// 读取共享内存段中的数据printf(Data read from shared memory: %s\n, shared_memory);// 解除文件的映射if (munmap(shared_memory, 1024) -1) {perror(munmap);return 1;}// 关闭文件close(fd);return 0;
}这个例子中我们打开了一个名为shared_memory的文件并将其映射到进程的虚拟地址空间中。然后我们读取了共享内存段中的数据并解除了文件的映射。 两个进程间进行通信
首先进程A创建一个共享内存段并将其映射到自己的虚拟地址空间中
#include sys/mman.h
#include fcntl.h
#include stdio.h
#include unistd.h
#include string.hint main() {int fd;char *shared_memory;const char *message Hello from Process A!;// 创建或打开一个文件fd open(shared_memory, O_CREAT | O_RDWR, 0666);if (fd -1) {perror(open);return 1;}// 调整文件的大小if (ftruncate(fd, 1024) -1) {perror(ftruncate);return 1;}// 将文件映射到进程的虚拟地址空间中shared_memory (char *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (shared_memory MAP_FAILED) {perror(mmap);return 1;}// 写入数据到共享内存段strcpy(shared_memory, message);// 解除文件的映射if (munmap(shared_memory, 1024) -1) {perror(munmap);return 1;}// 关闭文件close(fd);return 0;
}然后进程B打开同一个共享内存段并将其映射到自己的虚拟地址空间中
#include sys/mman.h
#include fcntl.h
#include stdio.h
#include unistd.hint main() {int fd;char *shared_memory;// 打开文件fd open(shared_memory, O_RDWR);if (fd -1) {perror(open);return 1;}// 将文件映射到进程的虚拟地址空间中shared_memory (char *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (shared_memory MAP_FAILED) {perror(mmap);return 1;}// 读取共享内存段中的数据printf(Data read from shared memory: %s\n, shared_memory);// 解除文件的映射if (munmap(shared_memory, 1024) -1) {perror(munmap);return 1;}// 关闭文件close(fd);return 0;
}在上面的例子中进程A创建了一个共享内存段并写入了数据Hello from Process A!。进程B打开了同一个共享内存段并读取了进程A写入的数据。
3.2 munmap
3.2.1 函数原型、参数及返回值 munmap函数用于解除对映射区域的映射。
函数原型如下
int munmap(void *addr, size_t length);参数 addr参数 指向要解除映射的起始地址。通常是通过mmap函数返回的映射区域的指针。 length参数 要解除映射的长度。通常是通过mmap函数传入的映射区域的长度。
返回值
munmap函数的返回值为0表示成功-1表示失败并设置errno来指示错误的原因。
3.2.2 注意事项
addr参数必须是一个有效的映射区域的起始地址否则解除映射会失败。length参数必须与原始映射时使用的长度一致否则解除映射会失败。解除映射后之前映射的内存区域将不再可访问对该区域的访问将导致段错误。解除映射后如果之前使用了MAP_SHARED标志并且有其他进程仍在访问该映射区域可能会导致意想不到的结果。解除映射后如果之前使用了MAP_ANONYMOUS标志并且没有保存映射区域的指针将无法再次访问该映射区域。
在使用munmap函数时需要确保解除映射的时机和范围是正确的避免出现内存泄漏或者访问非法内存的情况。
3.2.3 函数示例 下面是一个使用munmap函数解除映射的示例
#include stdio.h
#include stdlib.h
#include sys/mman.hint main() {int *data;size_t length sizeof(int) * 10;// 使用mmap函数创建映射区域data mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);if (data MAP_FAILED) {perror(mmap);exit(1);}// 在映射区域中写入数据for (int i 0; i 10; i) {data[i] i;}// 解除映射if (munmap(data, length) -1) {perror(munmap);exit(1);}// 尝试访问解除映射的内存区域printf(%d\n, data[0]); // 该行代码将导致段错误return 0;
}在这个示例中首先使用mmap函数创建了一个大小为10个int的映射区域并将其保存在data指针中。然后通过循环将0到9的数字写入映射区域。接下来使用munmap函数解除对映射区域的映射。最后尝试访问解除映射的内存区域这会导致段错误。
4. 父子进程mmap通信
4.1 具体步骤如下 父进程创建一个共享内存区域可以使用shm_open函数创建一个具名的共享内存对象也可以使用mmap函数将一个文件映射到内存中。 父进程使用fork函数创建子进程。 子进程通过继承父进程的共享内存的描述符或者文件映射的地址可以直接访问共享内存。 父子进程可以通过共享内存进行通信可以在共享内存中定义一个数据结构父进程和子进程通过读写该数据结构来进行通信。 父子进程需要使用同步机制例如信号量、互斥锁等来确保对共享内存的访问是安全的避免竞争条件和数据不一致的问题。 当通信完成后父进程和子进程需要使用munmap函数解除对共享内存的映射以释放资源。
4.2 示例
父子进程通过共享内存进行通信
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/mman.h
#include sys/wait.htypedef struct {int value;
} SharedData;int main() {int fd shm_open(/myshm, O_CREAT | O_RDWR, 0666);ftruncate(fd, sizeof(SharedData));SharedData* sharedData mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);close(fd);pid_t pid fork();if (pid 0) {// 子进程printf(Child process: value %d\n, sharedData-value);sharedData-value 100;printf(Child process: value %d\n, sharedData-value);exit(0);} else if (pid 0) {// 父进程sharedData-value 50;printf(Parent process: value %d\n, sharedData-value);wait(NULL);printf(Parent process: value %d\n, sharedData-value);munmap(sharedData, sizeof(SharedData));shm_unlink(/myshm);} else {perror(fork);exit(1);}return 0;
}4.3 代码解释
在这个示例中首先使用shm_open函数创建了一个具名的共享内存对象并设置了其大小为SharedData结构体的大小。然后使用mmap函数将共享内存映射到内存中并获取到共享内存的地址。接下来使用fork函数创建子进程。
在子进程中首先打印共享内存中的value值然后将其修改为100并再次打印。在父进程中首先将共享内存中的value值设置为50然后等待子进程退出。最后打印共享内存中的value值然后使用munmap函数解除对共享内存的映射并使用shm_unlink函数删除共享内存对象。
5. 非血缘关系进程间mmap通信
5.1 具体步骤如下 创建一个共享内存区域可以使用shm_open函数创建一个具名的共享内存对象也可以使用mmap函数将一个文件映射到内存中。 所有需要通信的进程都使用shm_open或者mmap函数打开或者映射同一个共享内存对象。 进程通过共享内存进行通信可以在共享内存中定义一个数据结构进程通过读写该数据结构来进行通信。 进程需要使用同步机制例如信号量、互斥锁等来确保对共享内存的访问是安全的避免竞争条件和数据不一致的问题。 当通信完成后进程需要使用munmap函数解除对共享内存的映射以及shm_unlink函数删除共享内存对象。
5.2 示例
无血缘关系的进程通过共享内存进行通信
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/mman.h
#include fcntl.h
#include sys/wait.htypedef struct {int value;
} SharedData;int main() {int fd shm_open(/myshm, O_CREAT | O_RDWR, 0666);ftruncate(fd, sizeof(SharedData));SharedData* sharedData mmap(NULL, sizeof(SharedData), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);close(fd);pid_t pid fork();if (pid 0) {// 子进程printf(Child process: value %d\n, sharedData-value);sharedData-value 100;printf(Child process: value %d\n, sharedData-value);exit(0);} else if (pid 0) {// 父进程sharedData-value 50;printf(Parent process: value %d\n, sharedData-value);wait(NULL);printf(Parent process: value %d\n, sharedData-value);munmap(sharedData, sizeof(SharedData));shm_unlink(/myshm);} else {perror(fork);exit(1);}return 0;
}5.3 代码解释
这个示例与前面的父子进程间mmap通信的示例类似但是在这里我们使用了具名的共享内存对象。无血缘关系的进程通过打开或者映射同一个具名的共享内存对象实现了共享内存的通信。其他的步骤和前面的示例相同。
需要注意的是在无血缘关系的进程间通信时需要确保共享内存对象的创建和打开的顺序是一致的以及共享内存的大小和数据结构的定义是一致的。此外还需要使用适当的同步机制来确保对共享内存的访问是安全的。
6. 结语
共享内存是一种用于进程间通信的机制它允许多个进程访问同一块内存区域从而实现高效的数据共享。在使用共享内存进行进程间通信时需要注意以下几个关键点 创建共享内存可以使用shm_open函数创建具名的共享内存对象也可以使用mmap函数将一个文件映射到内存中。创建共享内存时需要指定大小。 访问共享内存进程通过mmap函数将共享内存映射到自己的地址空间中从而可以直接读写共享内存中的数据。需要注意保证共享内存对象的创建和打开的顺序一致。 同步机制由于多个进程同时访问共享内存可能会导致竞争条件和数据不一致的问题因此需要使用适当的同步机制来确保对共享内存的访问是安全的。常用的同步机制包括信号量、互斥锁、条件变量等。 解除映射和删除共享内存当通信完成后进程需要使用munmap函数解除对共享内存的映射以及使用shm_unlink函数删除共享内存对象。
需要注意的是使用共享内存进行进程间通信需要考虑同步和数据一致性的问题。在实际使用中还需要根据具体需求进行适当的修改和扩展以确保通信的正确性和可靠性。
常用的函数和系统调用包括
shm_open创建或打开具名的共享内存对象。ftruncate设置共享内存的大小。mmap将共享内存映射到进程的地址空间中。munmap解除对共享内存的映射。shm_unlink删除具名的共享内存对象。
此外还可以使用其他的同步机制函数如sem_init、sem_wait、sem_post等来实现对共享内存的同步访问。