2017-04-16 54 views
0

我有兩個文件,我試圖通過共享內存IPC。我在兩個文件中使用類似的語句進行分配。在服務器文件:C內存映射結構數組泄漏

int fd; 
int size = MAX_LEN; 
int bigSize = sizeof(struct region)+ size * sizeof(struct client_message) + size * sizeof(struct server_message); 
    struct region *rptr = (struct region*)malloc(bigSize); 
    printf("region size: %d clientMessage size: %d serverMessage size: %d and the total size: %d\n", sizeof(struct region), size * sizeof(struct client_message), size * sizeof(struct server_message), bigSize); 
    fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 

    if (ftruncate(fd, bigSize) == -1) 
     printf("error creating ftruncate\n"); 

    rptr = mmap(NULL, sizeof(struct region), 
       PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 

我用下面的鏈接中的示例動態地分配共享存儲器: C Windows - Memory Mapped File - dynamic array within a shared struct

當我在此服務器while循環和增加Ĵ分配
struct client_message { 
    pthread_t client_id; 
    int question; 
}; 
struct server_message { 
    pthread_t client_id; 
    pid_t server_id; 
    int answer; 
}; 
struct region {  /* Defines "structure" of shared memory */ 
    int len; 
    struct client_message ptr_client_message[0]; 
    struct server_message ptr_server_message[0]; 
}; 

文件,

(rptr->ptr_client_message[(j)%size]).question = 30; 
(rptr->ptr_server_message[(j)%size]).answer = 20; 

我從客戶端文件中讀取它是這樣:

printf("rptr len is %d and question of client %d is: %d, answer of server is %d \n", size, k%size, (rptr->ptr_client_message[(k)%size]).question, (rptr->ptr_server_message[(k)%size]).answer); 

輸出被mindboggling: 從服務器終端獲得:

rptr len is 10 and question of client 0 is: 30, answer of server is 20 
rptr len is 10 and question of client 1 is: 30, answer of server is 20 
rptr len is 10 and question of client 2 is: 30, answer of server is 20 
... 

改變用於client_message陣列的10個元素,即,高達客戶端[MAX_LEN]

從客戶終端我得到:

rtpr len is 10 and question of client 0 is: 30, answer of server is 20 
rptr len is 10 and question of client 1 is: 30, answer of server is 30 
rptr len is 10 and question of client 2 is: 30, answer of server is 20 
rptr len is 10 and question of client 3 is: 30, answer of server is 30 
rptr len is 10 and question of client 4 is: 30, answer of server is 20 
rptr len is 10 and question of client 5 is: 30, answer of server is 30 
rptr len is 10 and question of client 6 is: 30, answer of server is 20 
rptr len is 10 and question of client 7 is: 30, answer of server is 20 
rptr len is 10 and question of client 8 is: 30, answer of server is 20 
rptr len is 10 and question of client 9 is: 30, answer of server is 20 
rptr len is 10 and question of client 0 is: 30, answer of server is 20 
rptr len is 10 and question of client 1 is: 30, answer of server is 30 
rptr len is 10 and question of client 2 is: 30, answer of server is 20 
rptr len is 10 and question of client 3 is: 30, answer of server is 30 
rptr len is 10 and question of client 4 is: 30, answer of server is 20 
rptr len is 10 and question of client 5 is: 30, answer of server is 30 
rptr len is 10 and question of client 6 is: 30, answer of server is 20 
rptr len is 10 and question of client 7 is: 30, answer of server is 20 
rptr len is 10 and question of client 8 is: 30, answer of server is 20 

因此,從另一個進程到達時,struct區域中的條目是混合的。我怎樣才能防止這一點?

+1

結構中不能有2個靈活的數組成員。基本上'rptr-> ptr_client_message'和'rptr-> ptr_server_message'是別名。 –

+0

謝謝,你可能會推薦任何改進?順便說一下,你怎麼知道這是肯定的,我的意思是任何c參考? –

+1

http://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p18:「作爲一種特殊情況,具有多個命名成員的結構的最後一個元素可能具有不完整的數組類型;這被稱爲靈活的陣列成員。「 –

回答

1

問題是你不能在一個結構中使用兩次zero length array trick

您在struct region中使用的技巧是GCC擴展,它允許您在結構中包含可變長度的數組。零長度數組作爲標題,然後你可以記住,你儘可能多地在內存上添加內存。

// This starts at rptr->client_message and advances two indexes. 
rptr->client_message[2] = ...; 

的問題是有另一個零長度立即陣列rptr->client_message後,rptr->server_message。所以當你寫信給rptr->client_message時,你會覆蓋rptr->server_message

讓我們簡化一下,你就會明白爲什麼。

struct region { 
    int len; 
    char ptr_client_message[0]; 
    char ptr_server_message[0]; 
}; 

以與您相同的方式初始化它。

size_t size = 4; 
struct region *rptr = malloc(sizeof(struct region) + size + size); 

現在我們似乎有兩個3字符串的地方。我們來添加一個。

rptr->ptr_server_message[0] = 'a'; 
rptr->ptr_server_message[1] = 'b'; 
rptr->ptr_server_message[2] = 'c'; 
rptr->ptr_server_message[3] = '\0'; 

printf("server_message: %s\n", rptr->ptr_server_message); 

這很好,它打印abc。現在我們來填充rptr->ptr_server_message

rptr->ptr_client_message[0] = '1'; 
rptr->ptr_client_message[1] = '2'; 
rptr->ptr_client_message[2] = '3'; 
rptr->ptr_client_message[3] = '\0'; 

printf("client_message: %s\n", rptr->ptr_client_message); 

這很好,它打印123。那麼rptr->ptr_server_message

printf("server_message: %s\n", rptr->ptr_server_message); 

也打印123!事實證明,他們指向相同的記憶。

// 0x7ff5f1404144 0x7ff5f1404144 
printf("%p, %p\n", rptr->ptr_client_message, rptr->ptr_server_message); 

因此,在一個結構中不能有兩個零長度的數組。

+0

謝謝,這就是伊利亞埃米利婭所說的,但那麼爲什麼這個程序已經連續多次奏效?它並沒有解釋爲什麼該程序已經連續5個點工作,但是將客戶端1客戶端3和客戶端5的結果混合在一起( –

+0

@ b.g)。歡迎來到[未定義行爲]的精彩世界(https://en.wikipedia.org/wiki/Undefined_behavior)! Plus多進程共享內存引入各種時序問題。沒有看到你的代碼,我無法推測可能發生的事情,但它沒有實際意義,因爲你的代碼已經進入垃圾進/垃圾出境的境界。這就像開着一輛矇住眼睛的車,在路上轉彎,想知道「爲什麼在我墜毀之前的三分鐘裏,我需要*爲什麼不是四個或兩個? – Schwern