Linux系统开发中多进程交换数据,共享内存高效且实现与容量占用相关

在 linux 系统开发中,时常需要在多个进程之间进行数据交换。在多个进程之间交换数据有多种方法,然而其中最高效的方法就是共享内存。

Linux系统开发中多进程交换数据,共享内存高效且实现与容量占用相关

使用 df -h 命令可以看到 /dev/shm 的容量情况。实际上它不会真正占用这块内存。如果在 /dev/shm/ 下没有任何文件,那么它占用的内存实际上是 0 字节。只有在使用 shm_open 文件时,/dev/shm 才会真正占用内存。

在Linux系统使用共享内存,一般用到以下几个函数:

创建或打开一个共享内存对象,通过指定的名称、打开标志和模式来进行操作。可以指定一个已存在的共享内存对象进行打开操作,也可以创建一个新的共享内存对象。具体的操作取决于打开标志 oflag 的设置。同时,mode 参数用于设置共享内存对象的访问权限。
- 第六个参数是 off_t 类型的 offset。
int 函数 munmap ,其参数为一个 void 类型的指针 addr 和一个 size_t 类型的长度 length ,用于执行解除映射操作。
调用 shm_unlink 函数,参数为一个字符指针类型的常量 name 。
函数 ftruncate 带有两个参数,一个是文件描述符 fd,另一个是长度值 length ,它用于截断文件到指定的长度。

int shm_open(const char *name, int oflag, mode_t mode);

功能说明:shm_open 能够创建或者打开共享内存文件。笔者觉得 shm_open 可能只是系统函数 open 的一种包装形式。其不同之处在于,shm_open 操作的文件必定位于 tmpfs 文件系统中,而常见的 Linux 发布版的 tmpfs 文件系统的存放目录为 /dev/shm。

返回值:成功返回fd>0, 失败返回fd

参数说明:

要打开或创建共享内存的文件名是 name。因为 shm_open 打开或操作的文件都在 /dev/shm 目录中,所以 name 不能带路径。例如,/var/myshare 这样的名称是错误的,而 myshare 是正确的,因为 myshare 不带任何路径。如果你必须在 name 中添加路径,那么需在 /dev/shm 目录创建一个目录。比如,若要创建 bill/myshare 的共享内存文件,需先在 /dev/shm 目录创建 bill 这个子目录。因为不同厂家发布的 linux 系统的 tmpfs 位置或许不是 /dev/shm,所以带路径的名称在其他环境下可能打开不成功。

打开的文件操作属性为 O_CREAT、O_RDWR、O_EXCL 进行按位或运算后的组合

mode:文件共享模式,例如 0777

请提供需要改写的横线下的句子呀,你没有给出具体内容呢。

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

功能说明:打开的文件会被映射到内存。通常是把 shm_open 打开的文件映射到内存,同时也能够把硬盘上通过 open 函数打开的文件映射到内存。此函数仅仅是把文件映射到内存里,这样我们就能以操作内存指针的方式来对文件数据进行操作。

参数说明:

addr 指的是要将文件映射到的内存地址,通常情况下应该传递 NULL ,以便由 Linux 内核来指定。

length:要映射的文件数据长度。

映射的内存区域的操作权限,也就是保护属性,包含 PROT_READ、PROT_WRITE 以及 PROT_READ|PROT_WRITE 。

标志位参数 flags 包含 MAP_SHARED、MAP_PRIVATE 以及 MAP_ANONYMOUS 。

建立共享是用于进程间通信的。如果没有这个标志,那么别的进程即使能够打开文件,也无法看到数据。

MAP_PRIVATE: 只有进程自己用的内存区域

MAP_ANONYMOUS:匿名映射区

用来建立映射区的文件描述符,是通过 shm_open 打开或者 open 打开的文件。

映射文件相对于文件头有一个偏移位置,这个偏移位置叫做 offset ,并且这个偏移位置应该按照 4096 字节来进行对齐。

成功时返回映射的内存地址指针,可利用此地址指针对映射的文件内容进行读写操作,读写文件数据就像操作内存一样;失败时则返回 NULL。

请提供需要改写的横线下的句子呀,没有具体内容呢。------

int munmap(void *addr, size_t length);

功能说明:要取消内存映射,其中 addr 是通过 mmap 成功返回的地址,length 是需要取消的内存长度。munmap 仅仅是将映射的内存从进程的地址空间中撤销掉。如果不调用这个函数,那么在进程终止之前,该片区域将无法得到释放。

请提供需要改写的句子呀,你没有给出具体的横线下的句子呢。

int shm_unlink(const char *name);

删除 /dev/shm 目录的文件,由 shm_open 函数在 /dev/shm 目录创建的文件可通过 shm_unlink 删除。系统函数 unlink 能达到相同效果,使用 /dev/shm + name 可组成完整路径,但一般不这样做,因为系统的 tmpfs 位置或许不是 /dev/shm。用 shm_open 创建的文件,若不调用此函数进行删除操作,就会一直留存于 /dev/shm 目录中。这种情况会持续到操作系统重启,或者调用 linux 命令 rm 来执行删除操作为止。

------------------------------------------------------------------------------------------------------------

int ftruncate(int fd, off_t length);

功能说明:对文件大小进行重置。对于那些被 open 打开的文件,无论是通过何种方式打开的,包括 shm_open 打开的文件,都可以使用这个函数来进行操作。

好了,以下是共享内存操作的实践代码:

1.writer.c ,创建内存共享文件并写入数据。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MMAP_DATA_SIZE 1024
#define USE_MMAP 1
主函数的参数为整型的 argc 和字符型指针数组的 argv 。 主函数以整型的 argc 和字符型指针数组的 argv 作为参数。 整型的 argc 和字符型指针数组的 argv 被用作主函数的参数。 主函数接收整型的 argc 和字符型指针数组的 argv 作为参数。 整型的 argc 以及字符型指针数组的 argv 被当作主函数的参数。 主函数的参数包含整型的 argc 和字符型指针数组的 argv 。 主函数以整型的 argc 以及字符型指针数组的 argv 为参数。 整型的 argc 与字符型指针数组的 argv 被用于主函数的参数。 主函数接收包含整型的 argc 和字符型指针数组的 argv 作为参数。
{
        char * data;
创建或打开一个名为"shm-file0001"的共享内存对象,使用 O_CREAT|O_RDWR 标志,权限设置为 0777,将返回的文件描述符存储在 fd 变量中。
        if (fd < 0) {
                printf("shm_open failed!\n");
                return -1;
        }
        ftruncate(fd, MMAP_DATA_SIZE);
        if (USE_MMAP) {
                data = (char*)mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                if (!data) {
                        printf("mmap failed\n");
                        close(fd);
                }
                sprintf(data, "This is a share memory! %d\n", fd);
                munmap(data, MMAP_DATA_SIZE);
        }
        else {
            char buf[1024];
            int len = sprintf(buf,"This is a share memory by write! ! %d\n",fd);
            if (write(fd, buf, len) <= 0) {
                printf("write file %d failed!%d\n",len,errno);
             }  
        }
        close(fd);
        getchar();
        shm_unlink("shm-file0001");
        return 0;
}

编译:

使用 gcc 命令进行编译操作,将生成名为 writer 的可执行文件,编译源文件为 writer.c,并且链接了名为 rt 的库。

2. reader.c 打开内存共享文件读数据

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MMAP_DATA_SIZE 1024
int main(int argc,char * argv[])
{
        char * data;
定义一个整数变量 fd ,通过 shm_open 函数打开名为 "shm-file0001" 的共享内存,使用 O_RDWR 标志以读写模式打开,权限设置为 0777 。
        if(fd < 0)
        {
                printf("error open shm object\n");
                return -1;
        }
        
        data = (char*)mmap(NULL, MMAP_DATA_SIZE, PROT_READ, MAP_SHARED, fd, 0);
        if (!data) {
                printf("mmap failed!\n");
                close(fd);
                return -1;
        }
        printf(data);
        munmap(data,MMAP_DATA_SIZE);
        close(fd);
        getchar();
        return 0;
}

编译:

使用 gcc 命令进行编译操作,将生成名为 reader 的可执行文件,编译的源文件是 reader.c,同时链接了 -lrt 库。

如果写入程序调用了 shm_unlink("shm-file0001"),那么读者程序就无法打开共享内存文件。

笔者认为,共享内存和内存映射是两个不同的概念。并非使用 shm_open 打开的文件就一定要通过 mmap 来映射才能在进程间共享,即便使用常规的 Linux 函数 write 写入数据,也依然能够实现共享。

你可能想看:
« 上一篇
下一篇 »

相关推荐

FreeBasic:强大免费开源的64位basic编译器及应用优势

2025年05月10日

82阅读

脊柱侧弯矫正方法大盘点:运动康复、支具矫正等多种方式

2025年05月09日

88阅读

如何在winForm标题栏去掉标题文字且任务栏图标正常显示

2025年05月09日

86阅读

十一黄金周促销广告词大全,国庆购物狂欢等你来

2025年05月09日

78阅读

关闭快速编辑模式及插入模式,设置控制台指定文字颜色举例

2025年05月09日

63阅读

黄金搭档低糖高钙饮品包装及成分功效全解析,适合人群要知晓

2025年05月09日

91阅读