关于将共享内存与进程一起使用,我有几个问题。我查看了之前的几篇帖子,但无法准确地收集到答案。在此先感谢您的帮助。
我正在使用 shm_open + mmap,如下所示。此代码按预期工作,父子交替递增 g_shared->count(同步不可移植;它仅适用于某些内存模型,但对于我现在的情况来说已经足够了)。但是,当我将 MAP_SHARED 更改为 MAP_ANONYMOUS | MAP_SHARED,内存不共享,程序挂起,因为“标志”没有翻转。删除该标志可以确认每个进程从 0 到 10 的计数发生了什么(意味着每个进程都有自己的结构副本,因此有“计数”字段)。这是预期的行为吗?我不希望内存由文件支持;我真的很想模拟如果这些是线程而不是进程可能会发生什么(出于其他原因,它们需要是进程)。
我真的需要 shm_open 吗?由于进程属于同一层次结构,我可以单独使用 mmap 吗?我知道如果没有“执行人员”,这将是相当简单的,但是当“分叉”后面有一个“执行人员”时,我该如何让它工作?
我在 x86_64 (Intel i7-2600) 上使用内核版本 3.2.0-23。对于此实现,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;
}