프로세스와 공유 메모리 사용에 대한 몇 가지 질문이 있습니다. 이전 게시물을 여러 번 보았으므로 답변을 정확하게 수집하지 못했습니다. 귀하의 도움에 미리 감사드립니다.Linux/x86_64의 프로세스 간 공유 메모리
다음과 같이 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;
}
리눅스가 공유 메모리를 구현하기 위해 사용하는'tmpfs '는 가상 파일 시스템입니다. 거기에있는 파일의 내용은 전체적으로 메모리에 존재하며,'mmap'은'tmpfs'가 공유 메모리 "파일"의 내용을 저장하는 데 사용하는 동일한 물리적 페이지를 직접 매핑합니다. 'shm_open '은'/ dev/shm' (또는'tmpfs'가 마운트 된 곳)에 파일을 만들고/열고 파일 디스크립터를 되돌려주는 역할을합니다. 'open (..., O_CREAT)'를 사용하여 파일을 만들 수는 있지만 이식 할 수는 없습니다. 열린 파일 기술자는'execve'에서 살아남지 만 매핑은 그렇지 않습니다. –