미새문지

크래프톤 정글 week05, day41 - 시스템 콜 함수, IPC 본문

크래프톤 정글/TIL

크래프톤 정글 week05, day41 - 시스템 콜 함수, IPC

문미새 2024. 2. 21. 01:15
728x90

파일 디스크립터

  • 운영체제가 프로세스에서 파일, 소켓 파이프 등을 추적하기 위해 사용하는 추상적인 표현이며, 각 열린 파일이나 I/O 채널에 대해 고유한 정수 값을 할당하는 것
  • 파일 디스크립터는 운영체제의 리소스를 추상화해 프로세스가 이를 효율적으로 사용할 수 있도록 돕는 중요한 메커니즘이며, 리눅스나 유닉스 같은 운영체제에서는 표준입력(0), 표준출력(1), 표준오류(2) 등 기본적인 I/O 채널에 대한 파일 디스크립터가 미리 정의되어 있다.

시스템 콜 유형

  • 프로세스 제어(process Control) - 중요
    • 프로세스 실행, 생성, 대기 등
    • fork()
      • 현재 실행 중인 프로세스의 복제본을 생성하는 역할을 한다.
      • 성공적으로 수행되면, 부모 프로세스에게는 자식 프로세스의 PID를, 자식 프로세스에게는 0을 반환한다. 이를 통해 프로그램 내에서 부모 프로세스와 자식 프로세스를 구분할 수 있다.
      • 실패하면 부모 프로세스에 -1 반환하며, 이 때 자식 프로세스가 생성되지 않는다.
      • 멀티 프로세싱 환경이나 프로그램 통신을 위한 파이프를 생성하는 등의 작업에 사용되며, 쉘에서 외부 명령을 실행하거나 배치 작업을 수행하는 등의 작업에도 사용
    • exec()
      • 현재 실행 중인 프로세스의 주소 공간을 새로운 프로그램으로 완전히 대체한다.
      • 이는 프로세스가 다른 프로그램을 실행할 수 있게 해주는 중요한 메커니즘이며, 쉘, 복잡한 응용 프로그램 등을 구현할 수 있다.
      • exec() 시스템 콜은 성공하면 새로운 프로그램이 현재 프로세스의 주소 공간을 완전히 대체하기 때문에 리턴하지 않으며, 실패하면 에러 코드를 리턴하고 프로세스는 계속 실행된다.
      • 변형
        • execl(), execv(), execle(), execve(), execlp(), execvp() 등이 있다.
          • 대표적으로 execl, execv
          • execl : 새로운 프로그램의 경로와 전달할 인자들을 개별적으로 전달받고, 인자들은 NULL로 끝나야한다.
          • execv : 새로운 프로그램의 경로와 인자들의 배열을 전달받고, 인자들은 NULL로 끝나야한다.
    • wait()
      • 부모 프로세스가 자식 프로세스의 종료를 대기하는 역할
      • 부모 프로세스가 wait()를 호출하면, 운영 체제는 해당 프로세스를 ‘대기’ 상태로 변경하고, 자식 프로세스가 종료될 때 까지 부모 프로세스의 실행을 중지시킨다.
      • 자식 프로세스가 종료되면 운영 체제는 그 프로세스의 종료 상태를 회수하고, 부모 프로세스를 ‘실행 가능’ 상태로 변경해 실행을 계속한다.
      • wait() 시스템 콜은 프로세스의 종료 상태 정보를 받아올 수 있고 좀비 프로세스 라는 자원을 소비하는 프로세스를 방지할 수 있다.
    • exit()
      • 현재 실행 중인 프로세스를 종료하는 역할
      • 종료 상태 값을 인자로 받아 운영 체제에 전달하며, 부모 프로세스가 wait 시스템 콜을 통해 받아올 수 있다.
      • exit()가 호출되면, 운영 체제는 프로세스가 사용하던 모든 자원을 회수하고, 프로세스의 상태를 종료로 변경

  • 파일 조작(file manipulation) - 중요
    • 파일 열기, 읽기, 쓰기 등
    • open()
      • 파일을 열거나 새로운 파일을 생성하는 역할
      • 파일의 경로와 파일을 열 때의 모드(읽기, 쓰기 등), 그리고 필요한 경우 새 파일의 권한을 인자로 받는다.
      • 성공적으로 수행되면, 운영체제가 해당 파일에 할당한 파일 디스크럽터를 반환하며, 이 파일 디스크립터는 read, write, close 등의 시스템 콜에서 해당 파일을 참조하는데 사용된다.
    • read()
      • 열려 있는 파일에서 데이터를 읽어오는 역할을 한다.
      • 파일 디스크립터, 데이터를 저장할 버퍼 위치, 읽어올 바이트 수를 인자로 받는다.
      • 파일 뿐만 아니라, 파이프 터미널 등 다양한 유형의 입출력 리소스에서 데이터를 읽어오는 데 사용
    • write()
      • 열려있는 파일에 데이터를 쓰는 역할
      • 파일 디스크립터, 쓰려는 데이터가 있는 버퍼 위치, 쓰려는 바이트 수를 인자로 받는다.
      • open이 수행된 후에 반환되며, 특정 파일을 참조한다.
    • close()
      • 열려있는 파일을 닫는 역할
      • 파일 디스크립터를 인자로 받는다.

  • 장치 관리(device management) - 덜 중요
    • 디바이스 부착, 분리, 읽기, 쓰기 등
    • ioctl()
      • 입출력 장치의 특성을 제어하거나, 입출력 모드를 변경하거나, 특별한 연산을 수행하는 등의 작업에 사용
      • 파일 디스크립터, 명령 코드, 명령 코드에 따른 추가 인자를 받는다.
      • 사용처가 매우 넓고 다양하며, 디바이스 드라이버나 특정 장치에 의존적이다.
        • 예시) 터미널의 설정 변경, 디스크의 파티션 조작 등
    • read()
      • 파일 조작의 read 함수와 동일
    • write()
      • 파일 조작의 write함수와 동일

  • 정보 유지(information maintenance) - 덜 중요
    • 시간, 날짜 설정 등
    • getpid()
      • 현재 실행 중인 프로세스의 ID(PID)를 반환하는 역할
      • 프로세스 ID는 프로세스를 식별하기 위한 고유 번호이기 때문에 프로세스의 생명 주기 동안 변하지 않으며, 프로세스가 종료되면 다시 ID를 회수하고 필요에 따라 재사용한다.
      • 프로세스 ID는 프로세스 간 통신(IPC), 시그널 처리, 프로세스 상태확인 등 다양한 운영 체제의 기능에서 지정하거나 식별하는데 사용되기 때문에 프로그래밍에서 매우 중요한 역할
    • alarm()
      • 일정 시간이 지나면 프로세스에 시그널을 보내는 타이머를 설정하는 역할
      • 초 단위의 시간을 인자로 받는다.
      • alarm이 호출되면 운영체제는 해당 시간이 지난 후 프로세스에 SIGALRM 시그널을 보내고, 프로세스는 이 시그널을 받아 적절하게 처리할 수 있다.
      • 시간 제한이 필요한 작업을 수행하거나, 프로세스가 무한히 블로킹되는 것을 방지하는 등의 작업에 사용될 수 있다.
        • 예시) 네트워크 연결 시도에 시간 제한을 두거나, 사용자 입력 대기에 시간을 두는 등의 작업에 사용
    • sleep()
      • 프로세스의 실행을 일정 시간 동안 중지하는 역할
      • 초 단위의 시간을 인자로 받는다.
      • 프로세스가 일정 시간 동안 아무것도 하지 않고 대기해야 할 때 사용한다.
        • 예시) 다른 프로세스 아니면 시스템 이벤트를 기다리거나, 특정 조건이 만족될 때까지 대기하는 등의 상황에 사용
      • 하지만 CPU 시간을 효율적으로 활용하지 못하므로, 이를 대체할 수 있는 다른 방법이 있을 경우에 그 방법을 우선적으로 고려하는 것이 좋다.

  • 통신(communication) - 중요
    • 통신 연결 생성, 제거, 상태 정보 전달 등
    • pipe()
      • 두 개의 프로세스 간에 데이터를 전달하는 파이프를 생성하는 역할
      • 파일 디스크립터 두 개를 저장할 수 있는 배열을 인자로 받는다.
      • 호출되면 운영체제는 새 파이프를 생성하고, 배열의 첫 번째 위치에는 파이프의 ‘읽기’ 끝을 참조하는 파일 디스크립터를, 두 번째 위치에는 파이프의 ‘쓰기’ 끝을 참조하는 파일 디스크립터를 저장한다.
      • 파이프는 한 방향으로만 데이터를 전달할 수 있기 때문에 양방향의 경우에는 두 개의 파이프를 사용해야 한다. 또한 파이프는 부모 프로세스가 자식 프로세스를 생성하기 전에 미리 만들어져야 한다.
        • 이는 fork() 시스템 콜이 파일 디스크립터를 복제하기 때문에 pipe()로 생성된 파일 디스크립터가 자식 프로세스로 복제되어, 부모 프로세스와 자식 프로세스가 같은 파이프를 공유할 수 있기 때문이다.
    • shm_open()
      • 공유 메모리 객체를 생성하거나 열어서 프로세스 간에 데이터를 공유하는 역할을 한다.
      • 공유 메모리 객체 이름, 플래그(읽기, 쓰기, 객체 생성 등), 필요한 경우 새 객체의 접근 권한을 인자로 받는다.
      • 호출되면 운영체제는 지정된 이름의 공유 메모리 객체를 생성하거나 열고, 해당 객체에 대한 파일 디스크립터를 반환한다. 이 파일 디스크립터는 mmap() 시스템 콜을 통해 프로세스의 메모리 공간에 매핑될 수 있다.
        • 함수의 변형으로는 shm_unlink()가 있으며 반대로 공유 메모리 객체를 제거하는 역할을 한다.
      • shm_open(), shm_unlink(), mmap() 등의 시스템 콜은 함께 사용되어, 프로세스 간에 대량의 데이터를 효율적으로 공유하는데 사용될 수 있다.
    • mmap()
      • 파일이나 장치를 프로세스의 메모리 공간에 매핑하는 역할을 한다.
      • 매핑할 메모리의 시작 주소, 매핑할 바이트 수, 메모리 보호, 플래그, 파일 디스크립터, 파일 내의 오프셋을 인자로 받는다.
      • 호출되면 운영체제는 지정된 파일이나 장치의 지정된 부분을 프로세스의 메모리 공간에 매핑하고, 매핑된 메모리의 시작 주소를 반환한다.
      • mmap()는 파일을 메모리에 매핑해 파일 입출력을 메모리 접근으로 대체함으로써 입출력 성능을 향상시키는데 사용 가능하다.
      • 또한 공유 메모리를 구현하여, 프로세스 간에 데이터를 공유하는데 사용될 수 있는데, 이런 기능은 데이터베이스, 병렬 컴퓨팅, 고성능 네트워크 서버 등에서 중요한 역할을 한다.

 

프로세스 간 통신(Inter-Process-Communication, IPC)

  • 서로 다른 프로세스 간에 데이터를 주고 받는 메커니즘
  • 독립적으로 실행되는 프로세스들이 정보를 공유하거나 협업해야 하는 경우에 IPC 메커니즘을 사용한다.
  • 여러 형태
    • 파이프(Pipe) - 중요
      • 두 프로세스 간에 데이터를 전달하는 통신 메커니즘
      • 파이프는 ‘읽기’ 끝과 ‘쓰기’ 끝이 있는 단 방향 통신 경로이며, 한 프로세스는 파이프의 ‘쓰기’ 끝에 데이터를 쓰고, 다른 프로세스는 ‘읽기’ 끝에서 데이터를 읽는다.
      • 파이프는 주로 부모 프로세스와 자식 프로세스 간에 사용되며, fork()를 통해 생성된 자식 프로세스는 부모 프로세스의 파일 디스크립터를 상속 받기 때문에 파이프를 공유할 수 있으며, 이를 통해 부모와 자식 프로세스는 서로 통신이 가능하다.
    • 메세지 큐(Message Queue)
      • 프로세스 간에 메세지를 주고받는 데 사용되는 메커니즘
      • 메세지는 큐에 저장되고, 프로세스는 큐에서 메세지를 읽거나 쓸 수 있다.
      • 공유 메모리(Shared Memory) - 중요
      • 두 개 이상의 프로세스가 동일한 메모리 영역을 공유하는 방식
      • 공유 메모리는 빠른 데이터 교환을 가능하게 하지만, 동시 액세스를 제어하기 위한 별도의 동기화 메커니즘이 필요하다.
    • 소켓(Socket) - 중요
      • 네트워크를 통해 떨어져 있는 프로세스 간에 데이터를 주고 받는데 사용
      • 소켓은 같은 시스템 내의 프로세스 뿐만 아니라, 서로 다른 시스템에 있는 프로세스 간의 통신도 가능하게 한다.
      • 인터넷의 대부분의 통신은 소켓을 통해 이루어진다.
    • 시그널(Signal) - 중요
      • 한 프로세스가 다른 프로세스에게 특정 이벤트가 발생했음을 알리는 방법
      • 비동기적인 통신 방식이며, 프로세스는 시그널을 언제 받을지 알 수 없다.
    • 세마포어(Semaphore)
      • 프로세스 간 통신에서 동기화 문제를 해결하기 위해 공유 자원에 대한 접근을 관리하는데 사용되는 메커니즘
      • 세마포어는 공유 자원에 대한 ‘허용 가능한 최대 동시 접근 수’를 나타내는 정수 값이다.
      • 프로세스가 자원을 요청하면 세마포어 값이 감소하고, 자원을 반환하면 세마포어 값이 증가한다. 값이 0이라는 뜻은 모든 자원이 사용 중이라는 뜻이며, 추가적인 요청을 하는 프로세스는 자원이 사용 가능해질 때까지 대기해야 한다.
      • 세마포어를 통해 공유 자원에 대한 동시 접근을 제어하면, 데이터의 일관성을 보장하고 경쟁 조건을 방지할 수 있다.
    • 메모리 매핑(Memory Mapping)
      • 파일이나 장치를 프로세스의 메모리 주소 공간에 직접 매핑하는 기술
      • mmap() 시스템 콜을 사용하여 메모리 매핑을 수행하며, 이를 통해 프로세스는 파일을 메모리에서 직접 읽고 쓸 수 있다.
      • 이는 디스크 입출력 작업을 최소화하여 성능을 향상 시키고, 메모리 매핑을 통해 두 프로세스는 같은 파일을 공유 메모리처럼 사용해 데이터를 공유할 수 있다.
    • 경쟁 조건(Race Condition)
      • 두 개 이상의 프로세스나 스레드가 공유 자원에 동시에 접근하려고 할 때 발생하는 상황
      • 이런 상황에선 프로세스나 스레드의 실행 순서에 따라 결과가 달라질 수 있는데, 데이터의 불일치나 예측 불가능한 동작을 일으킬 수 있어 동기화 메커니즘을 사용해 경쟁 조건을 방지해야 한다.
        • 동기화 메커니즘 - 세마포어, 뮤텍스, 모니터
          • 모니터 : 공유 자원에 대한 접근을 동기화하는 방법을 제공하는 추상화된 데이터 타입 또는 모듈
          • 뮤텍스 : 상호 배제, 한 번에 하나의 스레드나 프로세스만이 특정 코드 블록이나 공유 리소스에 접근하도록 보장하는 역할

학습 시간 : 10 ~ 25시

728x90