我在使用進程共享內存方面有幾個問題。我看了幾個以前的帖子,無法精確地收集答案。在此先感謝您的幫助。Linux/x86_64上的進程之間的共享內存
我正在使用像下面這樣的shm_open + mmap。這段代碼按照父母和孩子交替增加g_shared-> count的方式工作(同步不是可移植的;它只適用於某些內存模型,但對於我現在的情況來說足夠好)。但是,當我將MAP_SHARED更改爲MAP_ANONYMOUS |時MAP_SHARED,內存不共享和程序掛起,因爲'標誌'不翻轉。刪除標誌可以確認每個從0到10的過程發生了什麼(意味着每個過程都有自己的結構副本,因此也包含'count'字段)。這是預期的行爲?我不希望內存被文件支持;我真的很想模仿可能發生的情況,如果它們是線程而不是流程(它們需要是其他原因的流程)。
我真的需要shm_open嗎?由於進程屬於同一個層次結構,我可以單獨使用mmap嗎?我知道如果沒有'exec',這將是相當直接的,但是如果在'fork'之後有'exec',我怎麼才能使它工作?
我使用的是x86_64的內核版本3.2.0-23(英特爾i7-2600)。對於這種實現,mmap是否與共享同一個全局對象的pthread共享內存一樣提供相同的行爲(正確性和性能)?例如,MMU是否將該段映射爲「可緩存」的MTRR/TLB屬性?
cleanup_shared()代碼是否正確?它泄漏了任何內存嗎?我怎麼檢查?例如,是否有相當於System V的'ipcs?'?
感謝, /Doobs
shmem.h:
#ifndef __SHMEM_H__
#define __SHMEM_H__
//includes
#define LEN 1000
#define ITERS 10
#define SHM_FNAME "/myshm"
typedef struct shmem_obj {
int count;
char buff[LEN];
volatile int flag;
} shmem_t;
extern shmem_t* g_shared;
extern char proc_name[100];
extern int fd;
void cleanup_shared() {
munmap(g_shared, sizeof(shmem_t));
close(fd);
shm_unlink(SHM_FNAME);
}
static inline
void init_shared() {
int oflag;
if (!strcmp(proc_name, "parent")) {
oflag = O_CREAT | O_RDWR;
} else {
oflag = O_RDWR;
}
fd = shm_open(SHM_FNAME, oflag, (S_IREAD | S_IWRITE));
if (fd == -1) {
perror("shm_open");
exit(EXIT_FAILURE);
}
if (ftruncate(fd, sizeof(shmem_t)) == -1) {
perror("ftruncate");
shm_unlink(SHM_FNAME);
exit(EXIT_FAILURE);
}
g_shared = mmap(NULL, sizeof(shmem_t),
(PROT_WRITE | PROT_READ),
MAP_SHARED, fd, 0);
if (g_shared == MAP_FAILED) {
perror("mmap");
cleanup_shared();
exit(EXIT_FAILURE);
}
}
static inline
void proc_write(const char* s) {
fprintf(stderr, "[%s] %s\n", proc_name, s);
}
#endif // __SHMEM_H__
shmem1.c(父進程):
#include "shmem.h"
int fd;
shmem_t* g_shared;
char proc_name[100];
void work() {
int i;
for (i = 0; i < ITERS; ++i) {
while (g_shared->flag);
++g_shared->count;
sprintf(g_shared->buff, "%s: %d", proc_name, g_shared->count);
proc_write(g_shared->buff);
g_shared->flag = !g_shared->flag;
}
}
int main(int argc, char* argv[], char* envp[]) {
int status, child;
strcpy(proc_name, "parent");
init_shared(argv);
fprintf(stderr, "Map address is: %p\n", g_shared);
if (child = fork()) {
work();
waitpid(child, &status, 0);
cleanup_shared();
fprintf(stderr, "Parent finished!\n");
} else { /* child executes shmem2 */
execvpe("./shmem2", argv + 2, envp);
}
}
shmem2.c(子進程):
#include "shmem.h"
int fd;
shmem_t* g_shared;
char proc_name[100];
void work() {
int i;
for (i = 0; i < ITERS; ++i) {
while (!g_shared->flag);
++g_shared->count;
sprintf(g_shared->buff, "%s: %d", proc_name, g_shared->count);
proc_write(g_shared->buff);
g_shared->flag = !g_shared->flag;
}
}
int main(int argc, char* argv[], char* envp[]) {
int status;
strcpy(proc_name, "child");
init_shared(argv);
fprintf(stderr, "Map address is: %p\n", g_shared);
work();
cleanup_shared();
return 0;
}
Linux用來實現共享內存的'tmpfs'是一個僞文件系統。這些文件的內容完全存在於內存中,並且它們直接映射「tmpfs」用於存儲共享內存「文件」內容的相同物理頁面。 'shm_open'的功能是在'/ dev/shm'(或者'tmpfs'掛載的任何地方)創建/打開一個文件,然後給你返回文件描述符。您可以使用'open(...,O_CREAT)'自己創建文件,但它不可移植。打開的文件描述符將在'execve'中存活,但映射不會。 – 2012-08-17 17:02:12