gpt4 book ai didi

linux - Linux/x86_64 上跨进程共享内存

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:40:39 31 4
gpt4 key购买 nike

我有几个关于在进程中使用共享内存的问题。我查看了之前的几篇帖子,但无法准确地收集到答案。预先感谢您的帮助。

  1. 我正在使用 shm_open + mmap,如下所示。此代码按预期工作,父子交替递增 g_shared->count(同步不可移植;它仅适用于某些内存模型,但现在对我的情况来说已经足够好了)。但是,当我将 MAP_SHARED 更改为 MAP_ANONYMOUS | MAP_SHARED,内存未共享且程序挂起,因为“标志”未翻转。删除标志确认每个进程从 0 计数到 10 发生了什么(暗示每个进程都有自己的结构副本,因此有“计数”字段)。这是预期的行为吗?我不希望内存由文件支持;我真的很想模拟如果这些是线程而不是进程(由于其他原因它们需要是进程)可能会发生什么。

  2. 我真的需要 shm_open 吗?由于进程属于同一层次结构,我可以单独使用 mmap 吗?我知道如果没有“exec”,这将相当简单,但是当“fork”后面有一个“exec”时,我该如何让它工作?

  3. 我在 x86_64 (Intel i7-2600) 上使用内核版本 3.2.0-23。对于此实现,mmap 是否提供与共享内存相同的行为(正确性和性能),其中 pthreads 共享相同的全局对象?例如,MMU 是否映射具有“可缓存”MTRR/TLB 属性的段?

  4. cleanup_shared() 代码是否正确?它是否泄漏任何内存?我怎么查?例如,是否存在与 System V 的“ipcs”等效的东西?

谢谢,/傻瓜

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 &lt 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 &lt 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;
}

最佳答案

  1. 传递 MAP_ANONYMOUS 会导致内核忽略您的文件描述符参数并为您提供私有(private)映射。这不是你想要的。

  2. 是的,您可以在父进程中创建匿名共享映射,fork,并让子进程继承映射,与父进程和任何其他子进程共享内存。不过,这显然无法在 exec() 中存活下来。

  3. 我不明白这个问题; pthreads 不分配内存。可缓存性将取决于您映射的文件描述符。如果它是磁盘文件或匿名映射,那么它就是可缓存内存。如果它是视频帧缓冲设备,则可能不是。

  4. 这是调用 munmap() 的正确方法,但我没有验证除此之外的逻辑。所有进程都需要取消映射,只有一个应该调用取消链接。

关于linux - Linux/x86_64 上跨进程共享内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12000168/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com