我在使用进程共享内存方面有几个问题。我看了几个以前的帖子,无法精确地收集答案。在此先感谢您的帮助。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