shared memory, 좀비 프로세스, 고아프로세스, set/get/putenv

sesame·2021년 12월 27일
0

교육

목록 보기
7/46

shared memory

프로세스에서 메모리는 해당 프로세스만이 사용하는 것이 일반적이다.
메모리에는 명령어, 지역변수, 동적 변수, 전역 변수와 같이 데이터가 존재하는데 그 프로세스만 접근할 수 있고 변경가능합니다.
이 데이터를 다른 프로세스에서 쓰일 수 있도록 만들 수 있는데 이를 공유메모리라고 한다.
서로 다른 프로세스가 특정 메모리를 공유하면 데이터를 더 빠르게 접근할 수 있고 데이터 복사와 같은 불필요한 오버헤드가 발생하지 않기 때문에 프로그램을 더 효율적으로 만든다.

오버헤드(overhead)
어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말함
예를들어, 10초 걸리는 기능이 간접적인 원인으로 20초걸린다면 오버헤드는 10초가 되는것

공유메모리의 생성
1. 최초 공유메모리 영역을 만드는 프로세스가 커널에 공유메모리 공간의 할당을 요청
2. 만들어진 공유메모리는 커널에 의해서 관리

이런 이유로 한번만들어진 공유메모리는 운영체제를 리부팅하거나, 직접 공유메모리 공간을 삭제시켜주지 않은한, 공유메모리를 사용하는 모든 프로세스가 없어졌다고 하더라도, 계속적으로 유지된다.

프로세스가 커널에게 공유메모리 공간을 요청하게 되면, 커널은 공유메모리 공간을 할당시켜주고 이들 공유메모리공간을 관리하기 위한 내부자료구조를 통하여, 이들 공유메모리를 관리

  • shmid_ds 라는 구조체에 의해서 관리되며 shm.h 에 정의되어 있음

    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값을 통해서 다른 여러개의 공유메모리들과 구분됨

좀비 프로세스

자식 프로세스가 부모 프로세스보다 먼저 종료되는 경우

좀비 프로세스 생성 이유

  • 자식 프로세스가 exit 시스템 콜을 호출하면서 종료하는 경우(이 프로세스에 관련된 모든 메모리와 리소스가 해제)
  • main함수에서 return문을 실행하면서 값을 반환하는 경우
    자식 프로세스가 종료된 이후에 부모 프로세스가 자식 프로세스의 상태를 알고 싶을 수 있기 때문에 커널은 자식 프로세스가 종료되더라도 최소한의 정보(PID, 프로세스 종료상태 등)를 가지고 있는다. 부모 프로세스가 좀비프로세스의 종료상태를 회수하게 되면 좀비 프로세스는 제거된다.

자식 프로세스의 소멸의 위해서는 부모프로세스가 운영체제에 자식 프로세스의 전달값을 요청해야함

  • 요청하는 방법
#inlcude <sys/wait.h>
pid_t wait(int *status);
//return: ok 종료된 자식 PID, 실패 -1

부모 프로세스가 커널에게 자식 프로세스가 종료할 때 건네준 값을 달라고 요청하는 함수
wait 함수가 호출되었을 때 이미 종료된 자식 프로세스가 있다면 자식 프로세스가 종료되면서 전달한 값(exit함수 인자값, main함수의 return에 의한 반환값)이 매개변수로 전달된 주소(int *status변수에 저장된다. 저장되면서 함수는 프로세스의 상태값을 얻어오고, task 구조체에서 해당 프로세스의 정보를 완전히 삭제
자식 프로세스가 종료되면서 전달한 값에는 다른 정보도 있기 때문에

  • WIFEXITED: 자식 프로세스가 정상 종료된 경우 true 반환
  • WECITSTATUS: 자식 프로세스의 전달 값을 반환
    을 이용하여 값 가져옴
wait(&status); //좀비가 되어있는 자식 프로세스를 wait문을 이용하여 거둬들임
if(WIFEXITED(status)) //자식프로세스가 정상종료했을 경우 실행(true 받았을 때)
{
    //자식 프로세스의 전달값을 반환
    printf("Child pass num: %d", WEXITSTATUS(status));
}

wait 호출 시점에 종료된 자식 프로세스가 없으면 blocking 상태에 빠짐

고아 프로세스

부모 프로세스가 자식 프로세스보다 먼저 종료되면 Init 프로세스가 자식 프로세스의 새로운 부모 프로세스가 된다.

Init 프로세스
Init은 리눅스 커널 부팅이 완료된 뒤 실행되는 첫 번째 프로세스
& 커널이 직접 실행하는 유일한 프로세스
& 부모프로세스를 가지지 않는 유일한 프로세스
& Init을 제외한 나머지 모든 프로세스의 조상

  • Init의 간략화한 동작 과정
  1. 파일 시스템 초기화(파일 마운트, 스왑 디바이스 관리, 가상 파일 시스템 마운트 등)
  2. 네트워크 및 기본적인 시스템 동작을 위한 시스템 서비스 실행
  3. 백그라운드 서비스 실행
  4. 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를 이용하여 확인해보면 값이 출력되지 않음을 확인할 수 있음

0개의 댓글