如何共享现有内存?

Mr *_*der 6 c posix shared-memory

我想编写一些void* share(void*, int)应该设置共享内存以在指针处共享数据的函数.

我的第一次尝试看起来像(没有支票等):

void* share(void *toBeShared, int size) {
    int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
    ftruncate(fd, size);
    return mmap(toBeShared, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
}
Run Code Online (Sandbox Code Playgroud)

但这似乎并不像我想的那样有用.第二次尝试是这样的:

void* share(void *toBeShared, int size) {
    void *mem = NULL;
    int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
    ftruncate(fd, size);
    mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
    memcpy(mem, toBeShared, size);
    return mem;
}
Run Code Online (Sandbox Code Playgroud)

这确实有效,但我需要复制整个数据,我想避免.

因此我的问题是:有没有办法分享已经分配的内存(如果可能的话,无需复制太多),如果可以的话,怎么办呢?

提前致谢.

PS:我已经看到了更多这些问题(例如这里这里),但那里没有给出答案.


编辑:

我想怎么用它:

typedef struct {
    char *name;
    int status;
} MyTask;

int main(int argc, char** argv) {
    MyTask* taskList = NULL, sharedTaskList = NULL;
    int length = 0;
    ...
    readFile(&taskList, &length, ...);
    sharedTaskList = share(taskList, length * sizeof(MyTask));
    // or maybe even better: without needing to assign it to new variable
    for(i = 0; i < NR_WORKERS; i++) {
        switch(pid = fork()) {
            //etc...
        }
    }
    ...
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*tch -4

\n

如何共享现有内存?

\n
\n\n

不要共享现有内存。获取一些(少量)“新鲜”共享内存并稍后使用(即填充或读取)它。

\n\n

假设您使用的是 Linux,请阅读shm_overview(7)

\n\n

我猜你的某些功能可能会失败。您应该测试每次调用是否失败,例如

\n\n
int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);\nif (fd<0) {perror("shm_open"); exit(EXIT_FAILURE);};\n
Run Code Online (Sandbox Code Playgroud)\n\n

等等。也许还可以使用strace(1)

\n\n
\n

有没有办法共享已经分配的内存

\n
\n\n

简短的回答,不!(或者不容易,并且不是以便携的方式)。通常,您会执行相反的操作:获取一些已知大小的共享段,并使用一些指针进入其中。(同一共享段在不同进程中可能有不同的虚拟地址,例如由于ASLR)。

\n\n

您可以将mmap(2)MAP_FIXED某些已使用的虚拟地址空间子段一起使用(这将覆盖并用新的映射替换映射,而不是共享现有映射!),但我建议避免这种情况。请注意,虚拟地址空间是在多个页面中管理的,因此无法共享一些未页面对齐的数据。因此,除非和都是页面对齐的share,否则您的功能是不可能的。您可以考虑 Linux 特定的mremap(2)toBeSharedsize

\n\n

换句话说,您的应用程序应该首先分配一些共享内存,然后在获得的共享段中放置/使用一些数据,而不是尝试共享一些现有的非共享虚拟内存范围。因此,您可能想要编写一些代码void* get_my_shared_memory();(假设大小是编译时常量,并且每个进程调用该函数一次,并且其生成的虚拟地址通常会因进程而异)

\n\n

在实践中,内存是一种有限的资源,而共享内存是一种稀缺且非常有限的资源。在大多数系统上,您只能共享几十兆字节......因此共享任意大量的内存是不合理的。

\n\n

也许您的整个应用程序可能只使用某些服务器,例如某些数据库服务器 \xc3\xa0 la PostGreSQL ,通过向该服务器发出请求(并使用DBMS 的ACID属性)来共享信息。或者您可以将其组织为一个监视进程,在管道、套接字或 fifos 上与从属进程交换消息(例如要处理的 URL)。但我们不知道您正在编写什么样的应用程序。

\n\n

顺便说一句,共享内存是不够的。您需要同步您的流程

\n

  • 您不能使用 MAP_FIXED 共享现有映射。如果使用MAP_FIXED,现有的映射将被丢弃。我根本没看到你回答了他的问题。(他为什么要读 shm_overview?你认为那里的内容与他的问题相关?) (2认同)