如何共享现有内存?

时间:2016-01-31 10:20:06

标签: 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);
}

但这似乎并不像我希望的那样有效。第二次尝试是这样的:

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;
}

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

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

提前致谢。

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

编辑:

我想如何使用它:

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;
}

1 个答案:

答案 0 :(得分:-4)

  

如何共享现有内存?

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

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

我猜你的一些功能可能会失败。您应该针对每次通话失败进行测试,例如

int fd = shm_open(SHM_NAME, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
if (fd<0) {perror("shm_open"); exit(EXIT_FAILURE);};

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

  

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

简短回答,不!(或者不容易,而不是以便携方式)。你通常会做相反的事情:获得一些已知大小的共享段,并使用一些指针。 (相同的共享段可能在不同的进程中具有不同的虚拟地址,例如由于ASLR)。

您可以在某些已使用的虚拟地址空间子网段上使用mmap(2)MAP_FIXED用新的覆盖&替换映射,而不是共享< em>现有的映射!),但我建议避免这种情况。请注意,虚拟地址空间是以页面的倍数进行管理的,因此无法共享某些非页面对齐的数据。因此,除非sharetoBeShared 页面对齐,否则size函数不可能。您可以考虑特定于Linux的mremap(2)

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

实际上,内存是一种有限的资源,共享内存是一种稀缺且非常有限的资源。在大多数系统上,你只能分享几十兆字节...所以共享任意大量的内存是不合理的。

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

BTW,共享内存是不够的。 您需要同步您的流程