细说linux IPC(三):mmap系统调用共享内存
发布日期:2021-08-17 10:07:46 浏览次数:43 分类:技术文章

本文共 3002 字,大约阅读时间需要 10 分钟。

        【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途】
        前面讲到socket的进程间通信方式。这样的方式在进程间传递数据时首先须要从进程1地址空间中把数据复制到内核,内核再将数据复制到进程2的地址空间中,也就是数据传递须要经过内核传递。这样在处理较多数据时效率不是非常高。而让多个进程共享一片内存区则攻克了之前socket进程通信的问题。共享内存是最快的进程间通信 。将一片内存映射到多个进程地址空间中,那么进程间的数据传递将不在涉及内核。
        共享内存并非从某一进程拥有的内存中划分出来的。进程的内存总是私有的。共享内存是从系统的空暇内存池中分配的,希望訪问它的每一个进程连接它。这个连接过程称为映射。它给共享内存段分配每一个进程的地址空间中的本地地址。
    mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后。进程能够向訪问普通内存一样对文件进行訪问。不必再调用read(),write()等操作。

函数原型为:

#include 
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
        当中參数addr为描写叙述符fd应该被映射到进程空间的起始地址,当指定为NULL时内核将自己去选择起始地址,不管addr是为NULL,函数返回值都是fd所映射到内存的起始地址;
        len是映射到调用进程地址空间的字节数,它 从被映射文件开头offset个字节開始算起,offset通常设置为0;
        prot 參数指定共享内存的訪问权限。可取例如以下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可运行), PROT_NONE(不可訪问)。该值常设置为PROT_READ | PROT_WRITE 。
        flags由下面几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,当中,MAP_SHARED(变动是共享的,对共享内存的改动全部进程可见) , MAP_PRIVATE(变动是私有的。对共享内存改动仅仅对该进程可见)   必选其一,而MAP_FIXED则不推荐使用 。
    munmp() 删除地址映射关系。函数原型例如以下:
#include 
int munmap(void *addr, size_t length);
        參数addr是由mmap返回的地址。len是映射区大小。
        进程在映射空间的对共享内容的改变并不直接写回到磁盘文件里。往往在调用munmap()后才运行该操作。能够通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。 msync()函数原型为:
#include 
int msync(void *addr, size_t length, int flags);
        參数addr和len代表内存区,flags有下面值指定,MS_ASYNC(运行异步写), MS_SYNC(运行同步写),MS_INVALIDATE(使快速缓存失效)。当中MS_ASYNC和MS_SYNC两个值必须且仅仅能指定一个,一旦写操作排入内核。MS_ASYNC马上返回,MS_SYNC要等到写操作完毕后才返回。假设还指定了MS_INVALIDATE,那么与其终于拷贝不一致的文件数据的全部内存中拷贝都失效。
        在使用open函数打开一个文件之后调用mmap把文件内容映射到调用进程的地址空间,这样我们操作文件内容仅仅须要对映射的地址空间进行操作。而无需再使用open。write等函数。
        使用共享内存的步骤基本是:
open()创建内存段;
用 ftruncate()设置它的大小。
用mmap() 把它映射到进程内存,运行其它參与者须要的操作;
当使用完时,原来的进程调用 munmap()然后退出。
以下来看一个实现:
server程序创建内存并向共享内存写入数据:
int sln_shm_get(char *shm_file, void **shm, int mem_len){    int fd;    fd = open(shm_file, O_RDWR | O_CREAT, 0644);//1. 创建内存段    if (fd < 0) {        printf("open <%s> failed: %s\n", shm_file, strerror(errno));        return -1;    }    ftruncate(fd, mem_len);//2.设置共享内存大小    *shm = mmap(NULL, mem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //mmap映射系统内存池到进程内存    if (MAP_FAILED == *shm) {        printf("mmap: %s\n", strerror(errno));        return -1;    }    close(fd);    return 0;}int main(int argc, const char *argv[]){    char *shm_buf = NULL;    sln_shm_get(SHM_IPC_FILENAME, (void **)&shm_buf, SHM_IPC_MAX_LEN);    snprintf(shm_buf, SHM_IPC_MAX_LEN, "hello share memory ipc! i'm server.");    return 0;}
client程序映射共享内存并读取当中数据:
int main(int argc, const char *argv[]){    char *shm_buf = NULL;    sln_shm_get(SHM_IPC_FILENAME, (void **)&shm_buf, SHM_IPC_MAX_LEN);    printf("ipc client get: %s\n", shm_buf);    munmap(shm_buf, SHM_IPC_MAX_LEN);    return 0;}
先执行server程序向共享内存写入数据,再执行客户程序。执行结果例如以下:
# ./server# ./clientipc client get: hello share memory ipc! i'm server.#
共享内存不像socket那样本身具有同步机制,它须要通过添加其它同步操作来实现同步,比方信号量等。同步相关操作在后面会有相关专栏具体叙述。

本节源代码下载:

最后今天祝各位单身程序员节日快乐!。!!!

转载于:https://www.cnblogs.com/claireyuancy/p/6809825.html

转载地址:https://blog.csdn.net/weixin_30846599/article/details/99207437 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Photoshop 更改图片颜色
下一篇:POJ 3254 简单状压DP

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月07日 16时37分56秒