6494 단어
32 분
[ OS ] 1. Process

프로세스란#

일반적으로 프로세스란 실행 중인 프로그램을 의미하며, 프로그램은 디스크 상에 저장된 명령어와 정적 데이터의 집합이다. 이 명령어와 데이터 묶음을 읽어 실행함으로써 프로그램에 생명을 불어넣는 역할을 하는 것이 운영체제이다. 운영체제는 CPU를 가상화하여 하나 또는 소수의 실제 CPU로 여러 개의 가상 CPU가 존재하는 듯한 환상을 만들어낸다.

이런 환상은 단일 프로세스를 실행한 후 얼마 동안 중단시키고 다른 프로세스를 실행하는 작업을 반복함으로써 이루어지며, 이러한 기법은 시분할(time sharing)이라 불린다. 시분할 기법 덕분에 원하는 수만큼의 프로세스를 동시에 실행할 수 있지만, CPU를 공유하다 보니 각 프로세스의 성능은 다소 저하된다.

여기서 CPU 가상화(프로세스를 실행한 후 일정 시간 중단시키고 다른 프로세스를 실행하는 작업)를 효율적으로 구현하기 위해서는 프로세스를 어떻게 전환시킬 것인지, 그리고 여러 프로세스 중 어떤 것을 먼저 실행하고 얼마나 시간을 줄건지가 중요하다. 이중 프로세스를 어떻게 전환시킬 것인지는 이번 포스팅을 통해 알아보고, 여러 프로세스 중 어떤 것을 먼저 실행하고 얼마나 시간을 줄건지는 다음 프로세스 스케줄링에서 알아볼 것이다.

프로세스의 개념#

운영체제는 실행 중인 프로그램의 개념을 제공하며, 이를 프로세스(process)라고 부른다. 프로세스는 실행되는 동안 접근했거나 영향을 받은 모든 자원의 집합으로, 쉽게 말해 프로그램이 실행될 때 다루는 메모리, 레지스터 등의 하드웨어 자원을 포함한다.

프로세스의 하드웨어 상태 중 구성 요소#

(프로세스가 접근할 수 있는)메모리#

우선, 프로세스의 가장 중요한 구성 요소는 프로세스가 접근할 수 있는 메모리이다. 명령어는 물론 실행 프로그램이 읽고 쓰는 데이터 역시 메모리에 저장되며, 이 주소 공간(address space)을 통해 프로세스는 필요한 모든 작업을 수행할 수 있다.

레지스터#

또한, 프로세스의 하드웨어 상태를 구성하는 또 다른 핵심 요소는 CPU 내부의 소량의 고속 메모리인 레지스터이다. 레지스터는 각기 고유한 역할을 수행하며, 데이터나 명령어를 저장하고 처리하는 데 사용된다.

프로그램 카운터 / 명령어 포인터(program counter, PC / instruction pointer, IP)#

프로그램이 실행될 때, CPU는 메모리에서 명령어를 순차적으로 가져와 실행한다. 이때 프로그램 카운터는 다음에 실행할 명령어의 메모리 주소를 가리키는 역할을 한다. 명령어를 실행하면 프로그램 카운터는 다음 명령어의 주소로 업데이트되어 다음 명령어를 가리키게 된다. 이런식으로 프로그램 카운터는 프로그램의 실행 흐름을 제어하게 된다.

프로그램 카운터는 분기(branch) 명령어를 실행할 때나, 서브루틴(subroutine)을 호출하거나 반환할 때와 같이 프로그램 흐름을 변경할 때 업데이트된다. 예를 들어, 분기 명령어를 실행하면 프로그램 카운터는 분기되는 목적지의 주소로 설정된다.

프로그램 카운터는 CPU의 제어유닛(Control Unit)에 의해 관리되며, 명령어를 가져오고 실행하는 데에 필수적인 역할을 한다.

스택 포인터(stack pointer)#

프로세스에는 또한 스택과 관련된 레지스터들이 존재한다. 스택 포인터는 후입선출(LIFO) 방식으로 동작하는 메모리 스택에서 현재 위치를 가리키며, 함수 호출 시 매개변수, 복귀 주소, 지역 변수 등이 스택에 저장되고 함수 실행 후 제거되는 과정을 관리한다.

스택 포인터(Stack Pointer, SP)는 메모리 스택(Stack)에서 현재 위치를 가리키는 역할을 한다. 스택은 데이터를 임시로 저장하는 메모리 구조로, 후입선출(LIFO, Last-In-First-Out) 방식으로 동작한다.

스택 포인터는 스택의 맨 위(가장 최근에 푸시된 데이터의 위치)를 가리키며, 스택에 새로운 데이터를 푸시(push)하거나 팝(pop)할 때마다 스택 포인터가 적절히 조정된다.

스택은 주로 함수 호출이나 임시 데이터 저장 등에 사용된다. 함수 호출 시 함수의 매개변수, 복귀 주소, 지역 변수 등이 스택에 저장되며, 함수 실행이 끝나면 이러한 데이터들이 스택에서 제거된다. 이러한 구조는 프로그램의 실행 흐름을 관리하고 함수 호출의 순서를 추적하는 데 도움이 된다.

스택 포인터는 스택에 데이터를 푸시하거나 팝할 때마다 업데이트되며, 데이터의 저장 및 제거가 스택의 맨 위에서 이루어지기 때문에 스택 포인터는 항상 스택의 최상단을 가리킨다.

스택 포인터는 CPU의 스택 연산 명령어(예: PUSH, POP)가 실행될 때 업데이트되며, 스택 기반의 작업을 지원하는 데 필수적이다. 스택은 임시 데이터의 저장소로 사용되므로, 스택 포인터는 프로그램의 실행 중에 계속 변경된다.

프레임 포인터(frame pointer)#

프레임 포인터는 함수 호출 시 생성되는 스택 프레임의 시작 위치를 가리키는 역할을 하여, 함수의 매개변수, 지역 변수 및 함수 호출이 끝난 후의 복귀 주소 등을 저장하는 데 사용된다. 프레임 포인터와 스택 포인터가 함께 사용됨으로써 함수 호출 및 반환 과정이 원활하게 이루어지고, 프로그램의 실행 흐름이 체계적으로 관리된다.

프레임 포인터(Frame Pointer, FP)는 스택 프레임(Stack Frame)의 시작 위치를 가리키는 레지스터이다. 스택 프레임은 함수가 호출될 때마다 생성되는 공간으로,

프레임 포인터는 함수가 실행되는 동안 해당 함수의 스택 프레임에 접근할 때 사용된다. 함수가 호출될 때마다 새로운 스택 프레임이 생성되고, 프레임 포인터는 새로운 스택 프레임의 시작 위치를 가리키도록 업데이트된다.

일반적으로 프레임 포인터는 함수의 스택 프레임에서 고정 위치에 있으며, 지역 변수나 매개변수에 대한 접근을 편리하게 해줍니다. 또한, 함수 호출이 여러 번 중첩될 때도 각 함수의 스택 프레임을 쉽게 참조할 수 있도록 도와준다.

프레임 포인터는 일반적으로 스택 포인터와 함께 사용된다. 스택 포인터는 현재 스택 프레임의 맨 위를 가리키며, 프레임 포인터는 현재 함수의 스택 프레임의 시작 위치를 가리킨다. 이 두 레지스터를 함께 사용하여 함수 호출 및 반환을 효율적으로 관리하고, 지역 변수 및 매개변수에 접근할 수 있다.


운영체제가 프로그램을 실행하는 방식(프로세스가 생성되는 방식)#

대체 텍스트

  1. 프로그램 코드, 정적 데이터 프로세스의 주소공간에 탑재(load)
  2. 특정 크기의 메모리 공간이 프로그램에 스택 용도로 할당
  3. 프로그램의 힙을 위한 메모리 영역 할당
  4. 입출력과 관계된 초기화 작업
  5. 프로그램의 시작지점(entry point), 즉 main()에서부터 프로그램 실행

프로그램 실행을 위해서 운영체제가 하는 첫 번째 작업은 프로그램 코드와 정적 데이터(static data, 예를 들어 초기값을 가지는 변수)를 메모리, 즉 프로세스의 주소 공간에 탑재(load)하는 것이다. 프로그램은 디스크 또는 요즘 시스템에서는 플래시 기반 SSD에 특정 실행 파일 형식으로 존재하며, 운영체제는 디스크의 해당 바이트를 읽어서 메모리의 어딘가에 저장한다.

이와 같이 코드와 정적 데이터가 메모리에 탑재된 후, 현대의 운영체제는 프로그램 실행 시 코드나 데이터가 필요할 때 필요한 부분만 메모리에 로드하는 방식(일종의 캐싱)을 채택한다. 자세한 방법은 이후 포스트에서 다룰 페이징(paging)이나 스와핑(swapping) 동작을 통해 이해할 수 있다.

코드와 정적 데이터가 메모리로 적재된 후, 프로세스를 실행하기 전에 운영체제가 수행해야 할 몇 가지 작업이 있다. 먼저, 특정 크기의 메모리 공간이 프로그램의 스택(run-time stack, or just stack) 용도로 할당된다. C 프로그램은 지역 변수, 함수 인자, 리턴 주소 등을 저장하기 위해 스택을 사용하며, 운영체제는 main() 함수의 인자인 argc와 argv 벡터를 활용하여 스택을 초기화한다.

이어, 운영체제는 프로그램의 힙(heap)을 위한 메모리 영역을 할당한다. C 프로그램에서 힙은 동적으로 할당된 데이터를 저장하기 위해 사용되며, 프로그램은 malloc()을 호출하여 필요한 공간을 요청하고, 사용 후에는 free()를 호출하여 메모리를 반환한다. 또한, 힙은 연결 리스트, 해시 테이블, 트리 등 크기가 가변적인 자료 구조를 저장하는 데 활용된다.

또한, 운영체제는 입출력과 관계된 초기화 작업도 수행한다. 예를 들어, Unix 시스템에서는 각 프로세스가 기본적으로 표준 입력(STDIN), 표준 출력(STDOUT), 표준 에러(STDERR)에 해당하는 세 개의 파일 디스크립터(file descriptor)를 갖도록 설정되어, 프로그램이 터미널로부터 입력을 읽고 화면에 출력을 할 수 있게 된다.

이와 같이 코드와 정적 데이터를 메모리에 탑재하고, 스택과 힙을 생성 및 초기화하며, 입출력 셋업과 관련된 작업을 모두 마치면, 마지막으로 운영체제는 프로그램의 시작 지점(entry point), 즉 main()에서부터 실행을 시작함으로써 CPU를 새로 생성된 프로세스에게 할당한다.

프로세스의 상태#

프로세스가 무엇인지, 그리고 어떻게 생성되는지를 알아보았다. 이제는 생성되고 난 후의 프로세스의 상태(state)에 대해 알아보자. 프로세스 상태를 단순화 하면 다음 세 상태 중 하나에 존재할 수 있다.

대체 텍스트

  • Running State
  • Ready State
  • Blocked State

Running State(실행 상태)#

실행 상태에서 프로세스는 프로세서에서 실행중이다. 즉, 프로세스는 명령어를 실행하고 있다.

Ready State(준비 상태)#

준비 상태에서는 프로세스는 실행할 준비가 되어 있지만 운영체제가 다른 프로세스를 실행하고 있는 등의 이유로 대기 중이다.

Blocked State(대기 상태)#

프로세스가 다른 사건을 기다리는 동안 프로세스의 수행을 중단시키는 연산이다.

예를 들어, 만약 프로세스가 디스크에 대한 입출력 요청을 하였을 때 프로세스는 입출력이 완료될 때까지 대기 상태가 되고, 다른 프로세스가 실행 상태로 될 수 있다.

프로세스는 운영체제의 스케줄링 정책에 따라 스케줄이 되면, 준비 상태에서 실행 상태로 전이한다. 실행 상태에서 준비 상태로의 전이는 프로세스가 나중에 다시 스케줄 될 수 있는 상태가 되었다는 것을 의미한다. 프로세스가 입출력 요청 등을 이유로 대기 상태가 되면 요청 완료 등의 이벤트가 발생할 때까지 대기 상태로 유지괸다. 이벤트가 발생하면 프로세스는 다시 준비 상태로 전이되고 운영체제의 결정에 따라 바로 다시 실행될 수도 있다.

이제 두 개의 프로세스가 어떻게 전이 될 수 있는지를 볼 수 있는 예를 하나 보자.

대체 텍스트

위 예에서는, 첫 번째 프로세스가 어느 정도 실행한 후에 입출력을 요청한다. 그 순간 프로세스는 대기 상태가 되고 다른 프로세스에게 실행 기회를 준다.

자세히 살펴보면, Process0은 입출력을 요청하고 요청한 작업이 완료되기를 기다린다. 프로세스는 디스크를 읽거나 네트워크로부터 패킷을 기다릴 때 대기 상태로 전이한다. 운영체제는 Process0이 CPU를 사용하지 않는다는 것을 감지하고 Process1을 실행시킨다. Process1이 실행되는 동안 입출력은 완료되고 Process0은 준비 상태로 다시 전이된다. 최종적으로 Process1 종료 후, Process0이 실행되어 종료된다.

프로세스 API#

프로세스 API는 운영체제가 프로세스의 생성, 제어, 종료 등과 관련된 작업을 쉽게 수행할 수 있도록 제공하는 함수나 명령어들의 모음이다. 간단히 말해, 프로세스 API를 사용하면 프로그램 내에서 새로운 프로세스를 만들어내거나(예: fork()), 다른 프로그램을 실행할 수 있고(예: exec()), 실행 중인 프로세스의 상태를 확인하거나 종료를 기다리는 작업(예: wait()) 등을 할 수 있다.

아까 우리가 살펴본 프로세스의 생성과정(프로그램 실행 과정)를 다시 보자.

  1. 프로그램 코드, 정적 데이터 프로세스의 주소공간에 탑재(load)
  2. 특정 크기의 메모리 공간이 프로그램에 스택 용도로 할당
  3. 프로그램의 힙을 위한 메모리 영역 할당
  4. 입출력과 관계된 초기화 작업
  5. 프로그램의 시작지점(entry point), 즉 main()에서부터 프로그램 실행

프로세스의 생성 5개의 과정 중에서 프로세스 API는 5번에 관여한다. 다시 말해, 프로세스 API는 프로세스의 생성, 실행, 종료, 통신에 관여한다. 여러 운영체제 중 Unix는 프로세스를 생성하기 위해서 fork()와 exec() 시스템 콜을 사용한다. wait()는 프로세스가 자신이 생성한 프로세스가 종료되기를 기다리기 원할 때 사용된다.

NOTE

시스템 콜(System Call)?
시스템 콜(System Call)은 유저 모드(User Mode)와 커널 모드(kernel Mode)간의 인터페이스로 작동한다. 여기서 유저 모드는 응용 프로그램이 실행되는 환경이고, 커널 모드는 운영체제의 핵심인 커널이 실행되는 환경이다.

유저 모드(User Mode)
응용 프로그램이 실행되는 환경이다.응용 프로그램은 시스템 콜을 사용하여 운영체제의 서비스에 접근한다. 이를 통해 파일 읽기/쓰기, 메모리 할당, 네트워크 통신 등과 같은 다양한 작업을 할 수 있다. 유저 모드에서는 프로세스가 직접 실행되고, 커널의 기능에 접근할 수 없다.

커널 모드(Kernel Mode)
운영체제의 핵심인 커널이 실행되는 환경이다. 시스템 콜은 유저 모드에서 실행중인 프로세스의 요청에 응답하여 커널 모드로 전환된다. 커널 모드에서는 시스템 콜에 의해 요청된 작업을 처리하고, 시스템 자원을 관리하며, 프로세스 간의 보호와 권한 관리를 수행한다. 커널 모드는 운영 체제의 핵심 기능을 실행하기 위해 더 높은 권한을 가지며, 직접적으로 하드웨어와 상호 작용할 수 있다.

fork() 시스템 콜#

운영체제는 프로세스 생성을 위해 fork 시스템 콜을 제공한다.

// p1.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("hello world (pid: %d)\n", (int)getpid());

    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        printf("hello, I am child (pid:%d)\n", (int)getpid());
    } else {
        // (main)
        printf("hello, I am parent of %d (pid:%d)\n", rc, (int)getpid());
    }

    return 0;
}
  • 실행 결과
prompt> ./p1
hello world (pid: 29416)
hello, I am parent of 29147 (pid:29146)
hello, I am child(pid:29147)
prompt>

프로세스는 fork() 시스템 콜을 호출한다. 생성된 프로세스는 호출한 프로세스의 복사본이다. fork() 호출 직후를 보자.

운영체제 입장에서 보면 프로그램 p1이 2개가 존재한다. 두 프로세스가 모두 fork()에서 리턴하기 직전이다. 새로 생성된 프로세스는 부모 프로세스라 불린다.(일반적으로 자식 프로세스가 존재하고, 생성된 프로세스를 부모 프로세스라 한다.) 부모 프로세스는 main()함수 첫 부분부터 시작하지 않았다. 자식 프로세스는 fork()를 호출하면서부터 시작되었다

그리고 보면 출력 순서가 이상한 걸 알 수 있다. 코드로는 child가 먼저 나오는게 맞는데 왜 이런 결과가 나올까? fork() 실행시점부터 프로세스의 분기가 일어났기때문에 누가 스케줄링이 될지는 아무도 모른다. 따라서 순서가 뒤죽박죽이다. wait라던가 다른 시스템콜이 있거나, 프로세스의 함수실행부분에서 다르게 처리하지 않는 이상 결과는 계속 섞여서 나온다.

NOTE

PID는 프로세스의 실행이나 중단과 같이 특정 프로세스를 대상으로 작업을 해야 할 경우 프로세스를 지칭하기 위해 사용한다.

자식 프로세스와 부모 프로세스는 동일하지 않다. 자식 프로세스는 자신의 주소 공간, 자신의 레지스터, 자신의 PC값을 갖는다. 그리고 자식 프로세스와 부모 프로세스는 fork() 시스템의 반환 값이 다르다. fork()로부터 부모 프로세스는 생성된 자식 프로세스의 PID를 반환받고, 자식 프로세스는 0을 반환받는다. 이 반환값의 차이로 인해, 부모와 자식 프로세스가 서로 다른 코드를 실행하는 프로그램을 쉽게 작성할 수 있다.

CPU 스케줄러(scheduler)는 실행할 프로세스를 선택한다. 스케줄러의 동작은 일반적으로 상당히 복잡하고 상황에 따라 다른 선택이 이루어지기 때문에, 어느 프로세스가 먼저 실행된다라고 단정하는 것은 매우 어렵다. 이 비결정성으로 인해 멀티 쓰레드 프로그램 실행 시 다양한 문제가 발생한다.

wait() 시스템 콜#

// p4.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        close(STDOUT_FILENO); // 표준 출력 파일이 닫혔기 때문에 첫번째 사용가능 파일 디스크립터
        open("./p4.output", O_CREATE | O_WRONLY | O_TRUNC, S_IRWXU);

        char *myargs[3];
        myargs[0] = strdup("wc");
        myargs[1] = strdup("p4.c");
        myargs[2] = NULL;
        execvp(myargs[0], myargs);
    } else {
        int rc_wait = wait(NULL);
    }
    return 0;
}
prompt> ./p1
hello world (pid:29146)
hello, I am child (pid:29147)
hello, I am parent of 29147 (pid:29146)
prompt>

부모 프로세스가 자식 프로세스의 종료를 대기해야 하는 경우도 발생할 수 있다. 이러한 작업을 위해 wait() 시스템 콜이 있다. 이 코드에서 부모 프로세스는 wait() 시스템 콜을 호출하여 자식 프로세스 종료 시점까지 자신의 실행을 잠시 중지시킨다. 자식 프로세스가 종료되면 wait() 은 리턴한다.

exec() 시스템 콜#

// p2.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("hello world (pid: %d) \n", (int)getpid());

    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        printf("hello, I am child (pid: %d)\n", (int)getpid());
    } else {
        // (main)
        int rc_wait = wait(NULL);
        printf("hello, I am parent of %d (rc_wait: %d) (pid: %d)\n", rc, rc_wait, (int)getpid());
    }

    return 0;
}
  • 실행 결과
prompt> ./p3
hello world (pid:29384)
hello, I am child(pid:29384)
29 107 1030 p3.c
hello, I am parent of 29384 (rc_wait:29384) (pid:29383)
prompt>

exec() 시스템 콜은 자기 자신이 아닌 다른 프로그램을 실행해야 할 때 사용한다. p2.c 의 fork() 시스템 콜은 자신의 복사본을 생성하여 실행한다. 자신의 복사본이 아닌 다른 프로그램을 실행해야 하는 경우에는 바로 exec() 시스템 콜이 그 일을 한다.

이 예에서 자식 프로세스는 wc 프로그램을 실행하기 위해 execvp() 시스템 콜을 호출한다. wc 프로그램은 단어의 개수를 세는 프로그램이다. 사실 이 예제 프로그램은 자신의 소스 파일인 p3.c를 인자로 하여 wc를 실행하고 소스 코드의 행 개수, 단어의 개수, 바이트의 개수를 알려준다.

exec() 시스템 콜은 다음과 같은 과정으로 수행된다. 실행 파일의 이름과 약간의 인자가 주어지면 해당 실행 파일의 코드와 정적 데이터를 읽어 들여 현재 실행중인 프로세스의 코드 세그멘트와 정적 데이터 부분을 덮어 쓴다. 힙과 스택 및 프로그램 다른 주소 공간들로 새로운 프로그램의 실행을 위해 다시 초기화된다. 그런 다음 운영체제는 프로세스의 argv와 같은 인자를 전달하여 프로그램을 실행시킨다. 새로운 프로세스를 생성하지는 않는다. 현재 실행중인 프로그램을 다른 실행중인 프로그램으로 대체하는 것이다. 자식 프로세스가 exec()을 호출한 후에는 p3.c는 전혀 실행되지 않은 것처럼 보인다. exec() 시스템 콜이 성공하게 되면 p3.c는 절대로 리턴하지 않는다.

// p4.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    int rc = fork();
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if (rc == 0) {
        close(STDOUT_FILENO); // 표준 출력 파일이 닫혔기 때문에 첫번째 사용가능 파일 디스크립터
        open("./p4.output", O_CREATE | O_WRONLY | O_TRUNC, S_IRWXU);

        char *myargs[3];
        myargs[0] = strdup("wc");
        myargs[1] = strdup("p4.c");
        myargs[2] = NULL;
        execvp(myargs[0], myargs);
    } else {
        int rc_wait = wait(NULL);
    }
    return 0;
}
  • 실행 결과
prompt> ./p4
prompt> cat p4.output
32 109 846 p4.c
prompt>
NOTE

파일 디스크럽터(File Descriptor)는 운영 체제에서 파일이나 소켓, 파이프 등의 I/O 리소스를 식별하는 데 사용되는 정수이다. 대부분의 운영 체제는 파일 디스크럽터를 사용하여 파일을 열고, 읽고, 쓰고, 닫는다. 주로 세 개의 표준 파일 디스크럽터가 사용되며, 다음과 같이 정의된다stdin (Standard Input): 프로그램에 입력을 제공하는 파일 디스크럽터이다. 일반적으로 키보드 입력이 이에 해당한다. 파일 디스크럽터 번호는 보통 0이다.

stdout (Standard Output): 프로그램에서 출력하는 파일 디스크럽터이다. 일반적으로 터미널에 출력된다. 파일 디스크럽터 번호는 보통 1이다.

stderr (Standard Error): 프로그램에서 오류를 출력하는 파일 디스크럽터이다. 일반적으로 터미널에 출력된다. 파일 디스크럽터 번호는 보통 2이다.이러한 표준 파일 디스크럽터 외에도, 프로그램이 파일을 열 때마다 새로운 파일 디스크럽터가 할당된다. 이 파일 디스크럽터를 통해 프로그램은 파일에 대한 읽기, 쓰기, 닫기 등의 작업을 수행할 수 있다. 파일 디스크럽터는 정수 값으로 표현되며, 0 이상의 값으로 할당된다.

출처#

  • Operating system three easy pieces
  • System Software Lab Konkuk Operating System Lecture
[ OS ] 1. Process
https://blog-full-of-desire-v3.vercel.app/posts/operating_system/os-1-process/
저자
SpeculatingWook
게시일
2024-07-02
라이선스
CC BY-NC-SA 4.0