【问题标题】:Resize POSIX shared memory. A working example调整 POSIX 共享内存的大小。一个工作示例
【发布时间】:2017-03-16 21:13:23
【问题描述】:

我在两个不同的应用程序之间的 POSIX 模型中有一个共享的动态数组。我希望能够在不复制的情况下更改其大小。不幸的是,我找不到正确的解决方案来增加和减少 C 语言中的 POSIX 共享内存。在网上,我发现了许多解释不佳的文档和可怜的例子。我设法找到了一些有趣的话题,但它们都不适合我:

  1. "Linux System Programming" - "Mapping Files into Memory" Part: "Resizing a Mapping" - 没有调整 SHM 大小的工作示例。

  2. How do I implement dynamic shared memory resizing? - 仅描述。没有例子。

  3. mremap function failed to allocate new memory - 最喜欢的答案出错了。

  4. Fast resize of a mmap file

  5. Characteristics of mremap function in Linux

  6. mremap function failed to allocate new memory

  7. c/linux - ftruncate and POSIX Shared Memory Segments - rszshm 根本不使用 mremap()。它改为复制内存。最糟糕的方式。

根据我对文档的理解,我开发了一个示例。不幸的是,它无法正常工作。请给我一个建议,我哪里错了。请给我一个有效的例子。

在文档中我发现我必须在 mremap() 之前使用 ftruncate(),但我找不到正确的语法来使用它们。此外,mremap() 适用于对齐的内存页面。这种情况下如何正确增加共享内存?

/* main.c */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <errno.h>

int main(void)
{
    size_t size_of_mem = 1024;
    int fd = shm_open("/myregion", O_CREAT | O_RDWR,
                      S_IRWXO | S_IRUSR | S_IWUSR);
    if (fd == -1)
    {
        perror("Error in shm_open");
        return EXIT_FAILURE;
    }

    if (ftruncate(fd, size_of_mem) == -1)
    {
        perror("Error in ftruncate");
        return EXIT_FAILURE;
    }

    void *shm_address = mmap(0, size_of_mem,
                             PROT_READ | PROT_WRITE | PROT_EXEC,
                             MAP_SHARED, fd, 0);
    if (shm_address == MAP_FAILED)
    {
        perror("Error mmapping the file");
        return EXIT_FAILURE;
    }

    /* Increase shard memory */
    for (size_t i=0; i<1024; ++i){

        /* Does 8 align memory page? */
        size_t new_size_of_mem = 1024+(8*i);

        if (ftruncate(fd, new_size_of_mem) == -1)
        {
            perror("Error in ftruncate");
            return EXIT_FAILURE;
        }

        /*
           mremap() works with  aligned memory pages.
           How to properly increase shared memory in this case?
        */
        void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE);
        if(temp == (void*)-1)
        {
            perror("Error on mremap()");
            return EXIT_FAILURE;
        }

        size_of_mem = new_size_of_mem;

    }

    return 0;
}

构建:

$ gcc -g -O0 -ggdb -pipe -Wall -Wextra -Wpedantic -Wshadow -march=native -std=c11 -o ./main ./main.c -lrt

运行:

$ ./main
Error on mremap(): Bad address

【问题讨论】:

  • 至少您必须根据页面大小来衡量大小。见getpagesize()sysconf()。而且,为了在进程之间共享内存,您必须找到一种将新大小传达给其他进程的方法。

标签: c linux shared-memory mmap


【解决方案1】:

您正在丢失分配给temp 的新分配/重新映射内存的地址。

这意味着,从 for 循环的第二个循环开始,您正在移动一个已经移动的内存。

检查mremap返回值后,可以将新地址重新赋值给shm_address指针。

void *temp = mremap(shm_address, size_of_mem, new_size_of_mem, MREMAP_MAYMOVE);
if(temp == (void*)-1)
{
    perror("Error on mremap()");
    return EXIT_FAILURE;
}

shm_address = temp;

【讨论】:

  • 非常感谢。现在它真的可以正常工作了。剩下的问题怎么样。 mremap() 适用于对齐的内存页。这种情况下如何正确增加共享内存?
  • 这是一个很大的问题。发布一个不同的问题,以便从一些 linux 管理大师那里得到一个很好的解释。我在这里可以说的是,如果调用者提供的 len 参数未在页面边界上对齐,则映射将向上舍入到下一个完整页面。这个添加的内存中的字节,在最后一个有效字节和映射结束之间,是零填充的。从该区域读取的任何内容都将返回零。
猜你喜欢
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 2014-10-08
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 1970-01-01
相关资源
最近更新 更多