共享内存中的指针

时间:2016-01-01 00:35:42

标签: c pointers ipc shared-memory mmap

我正在使用共享内存(shm_open / mmap)来跟踪某些状态。在我的共享内存中,我有结构:

typedef struct fim_t {
    uint64_t num_procs;
    uint64_t num_numa;
    int64_t *numa_nodes[MAX_FIM_NUMA];
    int64_t procs[MAX_FIM_PROC];
}fim_t;

我想要做的是在procs数组中加载进程ID,然后让numa_nodes数组指向procs数组值,这样我就可以在一个位置操作值并让它在所有引用中进行更改。我的理解是,将numa_nodes引用设置为procs数组的地址不应该是内存访问冲突,因为它们的地址都完全位于共享内存段中。但是当我尝试访问告诉我之前的语句必须为false的值时,我得到一个seg错误。

以下是示例代码:

int main(){
    int fd;
    int init_flag = 0;
    if((fd = shm_open("fim", O_RDWR | O_CREAT | O_EXCL, S_IRWXU)) > 0){
        printf("creating shared memory\n");
        init_flag = 1;
    } else {
        printf("opening shared memory\n");
        fd = shm_open("fim", O_RDWR, S_IRWXU);
    }
    if (-1 == fd) {
        printf("fd is negative\n");
        abort();
    }
    if ((1 == init_flag) && -1 == ftruncate(fd, sizeof(fim_t))){
        printf("ftruncate failed %d\n", errno);
        abort();
    }

    fim_t *fim = mmap(NULL, sizeof(fim_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(MAP_FAILED == fim){
        printf("mmap failed\n");
        abort();
    }
    if(init_flag){
        fim->num_procs = 1;
        my_rank = 0;
        for(int x=0;x<MAX_FIM_PROC;x++){
            fim->procs[x] = 0;
        }
        fim->numa_nodes[0] = &(fim->procs[0]);
    } else {
        my_rank = __sync_fetch_and_add(&(fim->num_procs),1);
        fim->procs[my_rank] = my_rank;
        fim->numa_nodes[0] = &(fim->procs[my_rank]);
    }
    printf("my rank is: %"PRId64"\n",my_rank);
    sleep(5);
    printf("my numa val is %"PRId64"\n",*fim->numa_nodes[0]);
    printf("rank %"PRId64" is going down\n", my_rank);
    // SHUTDOWN
    uint64_t active = __sync_sub_and_fetch(&(fim->num_procs),1);
    printf("num active is now %"PRId64"\n", active);
    close(fd);
    shm_unlink("fim");
    return 0;
}

我期望/希望发生的是我运​​行一个进程然后立即启动另一个进程并且第一个进程打印“my numa val is 1”(由于第二个进程设置numa_node [0]值)并且都退出干净。但是,第二个进程运行正常,但是在第一个进程中,对于numa_node [0](在休眠之后)的print语句中出现了错误(内存访问)。

所以这是我的问题:我做错了什么还是我的方法不可行?如果它不可行,是否有其他方法可以实现我正在寻找的结果?

2 个答案:

答案 0 :(得分:4)

您没有做任何事情来安排共享内存的所有用户将其映射到同一个虚拟地址。一些* nix系统默认会这样做,但大多数不会。

尝试将您的片段映射到固定地址(并处理失败 - 这可能不会成功) - 或者在共享内存中存储偏移量,而不是实际指针。

答案 1 :(得分:2)

  

我的理解是,将numa_nodes引用设置为procs数组的地址不应该是内存访问冲突,因为它们的地址都完全位于共享内存段中。

问题是不同的进程将共享内存映射到不同的地址。

fim_t *fim = mmap(NULL, sizeof(fim_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

fim在不同的进程中会有不同的值。打印出来检查一下。

这导致int64_t procs[MAX_FIM_PROC]元素的指针在不同的进程中不同。

fim is <addr1> in process 1
fim is <addr2> in process 2

&fim->procs[0] will be different in two processes

&fim->procs[0] is <addr1> + <offset> in process 1
&fim->procs[0] is <addr2> + <offset> in process 2

因为它们是不同的值,所以它们不能在进程之间共享。一个进程中的有效指针在另一个进程中无效。

有两种可能的解决方案。

  1. 强制共享内存映射到所有进程中的相同地址mmap可以选择完成此任务。然后,您可以跨进程共享指向共享内存中元素的指针。
  2. 不要在共享内存中共享指针。改为分享索引。