프로세스에서 메모리는 해당 프로세스만이 사용하는 것이 일반적이다.
메모리에는 명령어, 지역변수, 동적 변수, 전역 변수와 같이 데이터가 존재하는데 그 프로세스만 접근할 수 있고 변경가능합니다.
이 데이터를 다른 프로세스에서 쓰일 수 있도록 만들 수 있는데 이를 공유메모리라고 한다.
서로 다른 프로세스가 특정 메모리를 공유하면 데이터를 더 빠르게 접근할 수 있고 데이터 복사와 같은 불필요한 오버헤드가 발생하지 않기 때문에 프로그램을 더 효율적으로 만든다.
오버헤드(overhead)
어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말함
예를들어, 10초 걸리는 기능이 간접적인 원인으로 20초걸린다면 오버헤드는 10초가 되는것
공유메모리의 생성
1. 최초 공유메모리 영역을 만드는 프로세스가 커널에 공유메모리 공간의 할당을 요청
2. 만들어진 공유메모리는 커널에 의해서 관리
이런 이유로 한번만들어진 공유메모리는 운영체제를 리부팅하거나, 직접 공유메모리 공간을 삭제시켜주지 않은한, 공유메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도, 계속적으로 유지된다.
프로세스가 커널에게 공유메모리 공간을 요청하게 되면, 커널은 공유메모리 공간을 할당시켜주고 이들 공유메모리공간을 관리하기 위한 내부자료구조를 통하여, 이들 공유메모리를 관리
struct shmid_ds {
struct ipc_perm shm_perm; //공유메모리는 여러개의 프로세스가 동시에 접근 가능하므로, 파일과 같이 그 접근권한을 분명히 명시해줘야 한다.
int shm_segsz; //할당된 메모리의 byte 크기
time_t shm_dtime; //가장최근의 프로세스가 세그먼트를 attach한 시간
time_t shm_dtime; //가장최근의 프로세스가 세그먼트를 detach한 시간
time_t shm_ctime; //마지막으로 이 구조체가 변경된 시간
unsigned short shm_cpid; //이 구조체를 생성한 프로세스의 pid
pid unsigned short shm_lpid; //마지막으로 작동을 수행한 프로세스의 pid
pid short shm_nattch; //현재 접근중인 프로세스의 수
};
공유메모리에 접근을 하기 위해서는 고유의 공유메모리 key 를 통해서 접근가능, 이 key값을 통해서 다른 여러개의 공유메모리들과 구분됨
자식 프로세스가 부모 프로세스보다 먼저 종료되는 경우
자식 프로세스의 소멸의 위해서는 부모프로세스가 운영체제에 자식 프로세스의 전달값을 요청해야함
#inlcude <sys/wait.h>
pid_t wait(int *status);
//return: ok 종료된 자식 PID, 실패 -1
부모 프로세스가 커널에게 자식 프로세스가 종료할 때 건네준 값을 달라고 요청하는 함수
wait 함수가 호출되었을 때 이미 종료된 자식 프로세스가 있다면 자식 프로세스가 종료되면서 전달한 값(exit함수 인자값, main함수의 return에 의한 반환값)이 매개변수로 전달된 주소(int *status변수에 저장된다. 저장되면서 함수는 프로세스의 상태값을 얻어오고, task 구조체에서 해당 프로세스의 정보를 완전히 삭제
자식 프로세스가 종료되면서 전달한 값에는 다른 정보도 있기 때문에
wait(&status); //좀비가 되어있는 자식 프로세스를 wait문을 이용하여 거둬들임
if(WIFEXITED(status)) //자식프로세스가 정상종료했을 경우 실행(true 받았을 때)
{
//자식 프로세스의 전달값을 반환
printf("Child pass num: %d", WEXITSTATUS(status));
}
wait 호출 시점에 종료된 자식 프로세스가 없으면 blocking 상태에 빠짐
부모 프로세스가 자식 프로세스보다 먼저 종료되면 Init 프로세스가 자식 프로세스의 새로운 부모 프로세스가 된다.
Init 프로세스
Init은 리눅스 커널 부팅이 완료된 뒤 실행되는 첫 번째 프로세스
& 커널이 직접 실행하는 유일한 프로세스
& 부모프로세스를 가지지 않는 유일한 프로세스
& Init을 제외한 나머지 모든 프로세스의 조상
- Init의 간략화한 동작 과정
- 파일 시스템 초기화(파일 마운트, 스왑 디바이스 관리, 가상 파일 시스템 마운트 등)
- 네트워크 및 기본적인 시스템 동작을 위한 시스템 서비스 실행
- 백그라운드 서비스 실행
- GUI 쉘 실행
#include <stdlib.h>
//주어진 이름의 환경변수 값을 return
char *getenv(const char *name);
//return: ok 환경변수값, 실패 NULL, 이름이 존재하지만 값이 없는 경우 첫바이트가 NULL인 빈문자열
int putenv(const char *str);
//키값 전달하면 value 반환, 만약
int setenv(const char *key, const char *value, int rewrite);
//rewrite: 이미 같은 key 항목이 있을 때 새로운 값으로 변경할지 여부
//0이면 key값을 바뀌지 않는다.
//0이 아니라면 key값이 value로 변경
환경변수들을 환경안에 '이름=값'과 같은 형태의 문자열로 저장되어있다.
putenv와 setenv를 통해서 설정된 환경변수는 현재 프로그램과 그 프로그램에서 파생된(fork, exel)프로그램에만 적용되기 때문에 원래 쉘 돌아와서 echo를 이용하여 확인해보면 값이 출력되지 않음을 확인할 수 있음