
fd = shm_open(name, O_CREAT | ORDWR, 0666);
ftruncate(fd, 4096); // 4096 byte씩 읽고 쓰게 됨
mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); // memory-mapped 파일을 shared memory에 mapping
mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
fd로 지정된 파일에서 offset을 시작으로 length byte만큼 start 주소로 대응시킴. prot는 원하는 메모리를 설정하는 인자, flags는 대응된 객체의 타입, 대응 옵션, 대응된 페이지 복사본에 대한 수정이 해당 프로세스에서만 보일 것인지, 다른 참조 프로세스와 공유할 것인지를 지정
prot 인자
- PROT_EXEC : 페이지 실행 가능
- PROT_READ : 페이지 읽기 가능
- PROT_WRITE : 페이지 쓰기 가능
- PROT_NONE : 페이지 접근 불가능
flags
- MAP_FIXED : 지정된 주소 이외의 다른 주소를 선택하지 않음. 지정된 주소가 사용 불가능하면 mmap이 실패함. MAP_FIXED를 지정하면, start는 페이지 크기의 배수여야 한다. (잘 사용x)
- MAP_SHARED : 대응된 객체를 다른 모든 프로세스와 공유
- MAP_PRIVATE : 개별적인 copy-on-write 대응을 만듬. 다른 프로세스와 대응 영역을 공유하지 않음
librt(Realtime Extensions 라이브러리)
shared memory에서 shm_open과 mmap을 사용하기 위해 -lrt 옵션을 추가해주어야함
shared memory에 쓰는 역할 수행
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main() {
const int SIZE = 4096; // the size of shared memory
const char *name = "OS"; // the name of shared memory
const char *message_0 = "Hello, ";
const char *message_1 = "Shared Memory!\n";
int shm_fd; // the file descriptor of shared memory
char *ptr; // pointer to shared memory
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory
실제 공유되고 있는 memory size로, shm_fd의 크기 조절*/
ftruncate(shm_fd, SIZE);
/* map the shared memory object */
ptr = (char*)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
/* write to the shared memory */
sprintf(ptr, "%s", mesage, 0); // Hello,
ptr += strlen(message_0); // 문장을 write한 후, pointer를 이동시킴
sprintf(ptr, "%s", message_1); // Shared Memory!
ptr += strlen(message_1);
return 0;
}
$ gcc -o producer producer.c -lrt
shared memory를 읽는 역할
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
int main() {
const int SIZE = 4096; // the size of shared memory
const char *name = "OS"; // the name of shared memory
int shm_fd;
char *ptr;
/* create the shared memory object */
shm_fd = shm_open(name, O_RDWR, 0666);
/* map the shared memory object */
ptr = (char*)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
/* read from the shared memory object */
printf("%s", (char*)ptr);
/* remove the shared memory */
shm_unlink(name);
return 0;
}
$ gcc -o consumer consumer.c -lrt
전통적으로 유닉스는 파이프를 많이 사용
shared memory는 사용자가 일일이 shm_open, mmap, shm_unlink 등의 작업을 모두 수행해야 함
파이프는 2개의 프로세스가 단순히 communication하는 도구로 사용
파이프를 구현할 때 고려할 4가지
Ordinary Pipe: parent-child 관계를 가지며, 파이프를 만든 프로세스 외에는 접근 불가
Named Pipe: parent-child 관계를 갖지 않음. 여러 개 가질 수 있음
Ordinary Pipe에서 parent와 child는 각각 2개의 file description을 가짐(각각 송수신). 각각의 pipe는 one-way communication만 가능함(unidirectional). 양방향 통신을 하기 위해서는 one-way pipe를 2개 사용.
pipe(int fd[])
fd[0]: the read end of the pipe
fd[1]: the write end
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFFER_SIZE 25
#define READ_END 0
#define WRITE_END 1
int main() {
char write_msg[BUFFER_SIZE] = "Greetings";
char read_msg[BUFFER_SIZE];
int fd[2]; // file descriptor의 size=2, READ_END, WRITE_END
pid_t pid;
/* create the pipe */
pipe(fd);
pid = fork();
if (pid > 0) { // parent process, read할 필요 없음
close(fd[READ_END]);
/* write to the pipe */
write(fd[WRITE_END], write_msg, strlen(write_msg) + 1);
close(fd[WRITE_END]);
} else { // child process, write할 필요 없음
close(fd[WRITE_END]);
read(fd[READ_END], read_msg, BUFFER_SIZE);
printf("read %s\n", read_msg);
close(fd[READ_END]);
}
return 0;
}