2016-01-01 111 views
3

我正在使用共享內存(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; 

我想要做的就是特效數組中加載進程ID,然後有numa_nodes陣列點特效數組值,所以我可以在一個地方操作的價值和它在所有參考文獻中都有變化。我的理解是設置numa_nodes引用procs數組的地址不應該是內存訪問衝突,因爲它們的地址都完全在共享內存段內。然而,當我嘗試訪問這個值時,我得到一個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; 
} 

我希望/希望發生的將是我運行一個進程,然後立即開始另一個和第一處理打印「我的NUMA val爲1」是什麼(由於第二個進程設置numa_node [0]的值)並且都乾淨地退出。但是,第二個進程運行正常,但是在numa_node [0]的打印語句(睡眠之後)的第一個進程seg故障(內存訪問)。

所以這裏是我的問題:我做錯了什麼或者我的方法行不通?如果它不可行,是否有另一種方法來實現我期待的結果?

+1

每個進程將有一個不同的共享內存地址。如果您在一個進程中設置指針,它們將不會在另一個進程中有效。 – Barmar

回答

2

我的理解是,設置proc數組地址的numa_nodes引用不應該是內存訪問衝突,因爲它們的地址都完全在共享內存段內。

問題是,不同的進程映射共享內存到不同地址。

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. 不要共享共享內存中的指針。改爲分享索引。
4

您沒有做任何事情來安排共享內存的所有用戶將它映射到相同的虛擬地址。一些* nix系統默認會這樣做,但大多數不會。

要麼嘗試將您的段映射到固定地址(並處理失敗 - 這可能不會成功) - 或將偏移量存儲在共享內存中,而不是實際指針。