머리말
콘텐츠
한때 AT&T System V라고도 알려진 System V는 Unix 운영 체제의 여러 버전 중 하나입니다.
System V는 메시지 큐, 공유 공간 및 세마포의 세 가지 고급 프로세스 간 통신 메커니즘을 도입합니다.
공유 메모리는 프로세스 간 통신의 가장 빠른 방법인데, 그 이유는 통신하는 프로세스 pcb의 주소 공간의 공유 영역이 물리적 메모리의 한 조각에 동시에 매핑되고 그 위의 데이터가 직접 가상 주소를 통해 찾아 액세스, 이러한 프로세스 간 데이터 전송不再涉及到内核的系统接口的调用
공유 메모리를 신청하면 프로세스 1과 프로세스 2는 각각 해당 공유 메모리를 자신의 주소 공간에 붙이고 정상적으로 통신할 수 있다.
파이프 기반 프로세스 간 통신의 경우 읽기 및 쓰기와 같은 시스템 인터페이스를 호출해야 합니다. 쓰기 끝은 먼저 커널의 파일 버퍼에 데이터를 쓰고 읽기 끝은 버퍼에서 읽습니다. 이러한 작업은 모두 시스템 인터페이스를 호출합니다.
즉, 프로세스는 더 이상 커널로 들어가는 시스템 호출을 실행하여 서로의 데이터를 전달하지 않습니다.
1. 공유 메모리 데이터 구조
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
2. 공유 메모리 기능
- 공유 메모리 생성
int shmget(key_t key, size_t size, int shmflg);
매개변수
키: 공유 메모리 세그먼트 이름
크기: 공유 메모리 크기
shmflg: 9개의 권한 플래그로 구성되며 사용법은 파일을 생성할 때 사용되는 모드 플래그와 동일합니다
. 반환 값: 성공적으로 음이 아닌 정수를 반환합니다. , 즉, 공유 메모리 메모리의 식별 코드, 실패 시
shmflg에서 -1을 반환합니다.
- 키 생성 키
가 ftok 함수에 의해 획득되고 공유 메모리의 고유 식별 코드를 반환합니다.shmid
key_t ftok(const char *pathname, int proj_id);
- 프로세스 주소 공간에 공유 메모리 세그먼트 연결
void *shmat(int shmid, const void *shmaddr, int shmflg);
매개변수
shmid: 공유 메모리 식별자
shmaddr: 연결 주소 지정
shmflg: 두 가지 가능한 값은 일반적으로 0으로 설정되는 SHM_RND 및 SHM_RDONLY입니다
. 반환 값: 힙에서 공간을 여는 malloc과 유사하게 포인터를 성공적으로 반환합니다. -1을 반환
- 공유 메모리에서 프로세스 주소 공간 바인딩 해제
int shmdt(const void *shmaddr);
매개변수
shmaddr: shmat에 의해 반환된 포인터 반환
값: 성공하면 0, 실패하면 -1
참고: 현재 프로세스에서 공유 메모리 세그먼트를 분리한다고 해서 공유 메모리 세그먼트가 삭제되는 것은 아닙니다.
ipc 리소스는 프로세스가 실행될 때 해제되지 않습니다 . 종료하지만 프로세스를 따릅니다. 커널
은 시스템 인터페이스 free 명령을 사용하여 종료하거나 공유 메모리를 해제합니다.ipcrm shmid
- 공유 메모리를 제어하는 데 사용
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
매개변수
shmid: shmget에 의해 반환된 공유 메모리 식별 코드
cmd: 수행할 작업(3가지 가능한 값이 있음)
buf: 공유 메모리의 모드 상태 및 액세스 권한을 저장하는 데이터 구조를 가리킴
반환 값: 성공은 0을 반환, 실패는 반환 -1
3. 명령줄 보기 공유 메모리
ipcs -m
shmid : 공유 메모리 번호
소유자 : 작성자
perms : 권한
바이트 수 : 크기
nattch : 연결된 프로세스 수
status : 공유 메모리 세그먼트가 삭제되었지만 여전히 사용자가 사용 중임을 나타내는 "dest"가 표시됩니다. 필드가 SHM_DEST로 설정되면 메모리 "dest" 세그먼트의 모드가 표시됩니다.
4. 실험: 서버와 클라이언트 통신
실험적 현상
- 공통.h
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define PATH_NAME "/root/class101/linux/lesson20/sharememory"
#define PROJ_ID 18733213
#define SIZE 4097
- 서버.c
#include "common.h"
int main() {
key_t key = ftok(PATH_NAME, PROJ_ID);
if(key == -1) {
perror("ftok");
return 1;
}
printf("key: %x\n", key);
int shmid = shmget(key, SIZE, IPC_CREAT|IPC_EXCL|0644);
if(shmid == -1) {
perror("shmget");
return 2;
}
printf("shmid: %d\n", shmid);
sleep(5);
char* start = (char*)shmat(shmid, NULL, 0);
if(start == (void*)-1) {
perror("shmat");
return 3;
}
printf("shmat success...\n");
sleep(5);
while(1) {
printf("%s\n", start);
sleep(1);
}
shmdt(start);
sleep(5);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
- 클라이언트.c
#include "common.h"
int main(){
key_t key = ftok(PATH_NAME, PROJ_ID);
if(key == -1) {
perror("ftok");
return 1;
}
int shmid = shmget(key, SIZE, IPC_CREAT);
if(shmid == -1) {
perror("shmget");
return 2;
}
sleep(5);
char* start = (char*)shmat(shmid, NULL, 0);
if(start == (void*)-1) {
perror("shmat");
return 3;
}
sleep(5);
char ch = 'A';
while(ch<='Z') {
start[ch-'A'] = ch;
ch++;
sleep(1);
}
shmdt(start);
printf("%x\n", key);
return 0;
}
- 메이크파일
CC=gcc
all: server client
server: server.c
$(CC) -o $@ $^
client: client.c
$(CC) -o $@ $^
.PHONY: clean
clean:
rm -f server client
서버가 무한 루프로 인쇄하기 때문에 결국 수동으로 공유 메모리를 해제해야 합니다.
ipcrm -m 327680
5. 참고/반복
1. 공유 메모리 기능
공유 메모리 공유 메모리 의 生命周期随OS
작동 공유 메모리는 모든 프로세스 간 통신에 사용됩니다. 공유 메모리 생성에 권장되는 크기는 4KB의 정수배입니다. 그렇지 않으면 시스템이 4KB에 따라 정렬됩니다.不提供任何同步与互斥
双方彼此独立
速度最快的
2. 키 대 쉬미드
key: 사용자 계층에서 생성한 고유한 키 값 핵심 기능은 고유성을 구별하는 것으로 IPC 자원을 운용하는 데 사용할 수 없음
shmid: 시스템이 우리에게 반환하는 IPC 자원 식별자로 운용에 사용 IPC 리소스.
- 여러 프로세스가 동일한 공유 메모리 조각을 보게 하려면 어떻게 해야 합니까?
Key에 의한 고유한 구별 - A와 B가 동일한 키를 사용하도록 하는 방법
key_t ftok(const char* pathname, int proj_id)
3. 시스템 인터페이스
시스템에서 ipc를 보는 명령은ipcs
所有ipc资源都是随内核
예, 프로세스가 종료될 때 인터페이스가 릴리스/OS 재시작을 위해 호출되지 않는 한 프로세스가 종료될 때 자동으로 릴리스되지 않습니다.
명령 릴리스 ipc
ipcrm -m shmid
넷째, 루틴
// 키 생성
key_t ftok(pathname, proj_id);
// 공유 메모리 생성
int shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0644);
// 공유 메모리 후크 프로세스
char* start = shmat(shmid, NULL, 0);
// 연결 해제
shmdt(start);
// 해제됨
shmctl(shmid, IPC_RMID, NULL);