운영체제(3), Processes

2022. 12. 18. 00:55강의 내용 정리/운영체제

728x90
반응형

Processes


 

프로그램과 프로세스

프로그램

파일 시스템에 저장된 실행파일로 파일을 실행하면 메모리에 로딩돼서 실행된다.

 

프로세스

프로그램을 실행하는 주체로, cpu는 프로세스의 실행 순서를 결정하는 스케줄링의 작업도 진행한다. 프로세스 ID(PID)가 정수 숫자로 붙여진다. 이때 스케줄링은 어떤 순서로 작업을 해야 가장 효율적인지를 감안하여 알고리즘을 짠다.

 

프로세스는 프로그램의 실체인 인스턴스가 된다. 유닉스가 처음 등장했을 때의 가장 작은 실행 및 스케줄링 단위가 프로세스였다. 지금은 쓰레드가 가장 작은 단위이다.

 

메인 프레임 시절에는 프로세스라는 이름 대신 job이라고 불렀다. 최초의 OS는 IBM에서 만들었는데 이 당시에는 task라고 불렀다. 유닉스에서는 프로세스라고 이름을 정의한 것에서 이어져서 지금까지 프로세스라고 부르지만 여전히 RToS에서는 task라고 부른다.


Process Address Space

제일 밑에는 taxt segment(code segment)가 있다. 해당 구문에서 instruction이 존재하게 된다. 그 위에 data segment가 있다. 이는 프로그램이 실행되는 동안 항상 저장되어있는 변수가 저장되어있다. 해당 공간에서는 static data(전역 변수)가 저장된다. 지역변수는 함수가 호출될 때 생성되기에 다른 공간인 stack에 존재하게 된다. stack에서는 거꾸로 증가하는 식으로 이뤄진다. Heap은 동적으로 생성되는 변수들이 저장되는 공간으로 DMA를 통해 생성되는 메모리이다.

 

함수가 호출될 때 가장 먼저 SP의 탑에는 return address가 저장된다. 이후 파라미터를 순차적으로 집어넣는다. 이때 집어넣는 순서는 언어별로 다르다. Function call할 때마다 stack의 메모리가 점차 증가한다. 재귀적으로 구성한 뒤 리턴을 하지 않으면 스택오버플로우가 발생하는 이유가 이 때문이다.

 

모든 프로세스는 가장 밑 번지가 0번지이다. 이는 가상메모리이기 때문이다.


State diagram

프로그램이 실행되면 프로세스가 적어도 하나가 만들어진다. 가장 먼저 프로세스의 state는 new가 된다. 이 프로세스가 실행 가능한 상태가 되면 ready가 된다. Ready 상태인 여러 프로세스를 고르는 작업은 스케줄링이다. 이후 ready 상태의 한 프로세스를 cpu에 올리는 작업을 디스패치라고 한다. 운영체제 내부에서 위와 같이 하는 작업을 scheduler dispatch라고 한다. 만약 interrupt가 발생하는 경우에는 프로세스는 ready 상태가 된다. 프로그램이 끝나면 terminated 상태가 되어서 이를 종료하는 작업을 한다. 프로세스가 차지하던 메모리를 반환하는 동작을 한다. I/O or event wait을 하면 waiting 상태가 된다. 이후 I/O가 끝나기를 기다리거나 할 때 waiting 상태이다. 외부 패킷이 도착하거나 키보드 입력 등의 이벤트가 완료되면 ready 상태가 된다.

 

Ready 상태와 waiting 상태의 차이를 확실하게 알아야한다. Waiting은 I/O 장치나 event가 모두 수행되기 전까지는 수행되기 어려운 상태이다. Ready는 수행될 수 있는 상태이지만 스케줄되기를 기다리는 상태이다.


Linux example

ps를 입력 시 프로세스의 상태를 알려준다. S은 waiting이다. T는 사용자의 명령어에 의해 중단된 상태이다. D는 메인메모리에 존재하지 않는 상태이다. Z는 프로세스가 종료는 됐는데 커널에 남아있는 상태를 의미한다.


Process Control Block(PCB)

운영체제가 프로세스를 ready, running, waiting 상태 등등 모든 프로세스와 관련된 정보를 저장하고 관리하는 구조이다. 리눅스에서는 task_structure라는 이름으로 관리되고 있다.

 

Task_struct는 프로세스 id, 상태, 프로세스가 생성한 자식 프로세스, 현재 프로세스가 오픈한 파일, 어드레스 스페이스 등등의 정보를 가지고 있다. Task_struct는 링크드 리스트 큐의 형태로 관리되고 있다. 운영체제에서는 PCB라고 정의한다.


Context Switch (CPU Switch)

CPU는 하나인데 프로세스 0가 수행되다가 프로세스 1이 수행되면 cpu의 상태/컨텍스트를 바꾸는 것이기에 이를 Context Switch, CPU Switch라고 한다. 프로세스 0가 실행되다고 interrupt가 걸리거나 시스템콜을 요청하면 OS가 수행된다. 현재 프로세스의 상태를 PCB0에 이러한 상태를 저장한다. 이때 저장되는 state는 레지스터들을 의미한다. 이후 P1으로 cpu의 컨텍스트를 바꾸기 위해 PCB1에 있는 상태를 다시 로드한다. 이후 프로세스1이 실행된다. 또 interrupt나 system call가 발생하면 프로세스1이 수행되던 상태(cpu에 저장되어있는 레지스터)를 저장한다. 이러한 과정이 프로세스마다 반복적으로 동작한다.

 

Interrupt가 비동기적으로 발생하기도 하고, 시스템콜을 요청하는 경우에는 동기적으로 동작한다. PCB에는 해당 프로세스에 대한 정보가 매우 많이 있다. 그 중에 레지스터들의 값을 저장하는 부분을 cpu 레지스터에 넣는다. PCB에는 엄청 다양한 데이터들이 있는데 그 중 register 부분에 있는 내용에 대해 save, reload한다.

 

Idle은 waiting이거나 ready 상태로 실행이 안되는 상태를 의미한다.

 

Cf) 디스패치는 context switching 중 하나의 작업이다.


Administrative overhead

Context switching을 하게 되면 캐쉬메모리가 매번 새로운 프로세스로 flushing된다. 프로세스를 순차적으로 수행하면 context switching을 하지 않아도 되는데 context switching은 성능 상 부담이 될 수 있다.

 

성능면에서는 오버헤드가 발생되지만 response time 측면에서 훨씬 우수하기 때문에 Context switching을 사용한다.

 

Context switch overhead를 줄이고자 하는 노력이 있다. 과거 overhead를 가장 줄인 것이 UltraSPARC이 된다. 지금은 intel cpu가 가장 빠르다. Cpu를 여러 개 사용해서 이를 네트워크로 연결하는 경우에도 성능이 좋아진다.

어플리케이션에 따라 다르겠지만 전형적으로 초당 100s ~ 1000s 만큼 수행한다.

 

Cf) overload: 과부화 // overhead: 부담, 지불하지 않아도 되는데 어쩔 수 없이 내는 비용

 

Ctxt는 context switching 횟수이다.


중간에 배운 내용 되짚어보기

 

프로그램과 프로세스의 차이, 프로세스의 메모리 어드레스 스페이스, 프로세스와 관련된 모든 정보를 저장하는 정보를 PCB라고 부른다. 리눅스에서는 task_struct로 관리한다. 프로세스의 상태 도표, ready, waiting, running을 반복하며 동작하는데 프로세스가 바뀌는 것을 context switching이라 한다. 스케줄링, 디스패치 등의 작업


Scheduler

스케줄링을 하는 주체로 OS가 하는 일이다. 과거에는 롱텀/숏텀/미디움 스케줄링을 구분했었다.

 

Long-term scheduler 

Long-term 스케줄링(job scheduler)은 파일 시스템 중 어떤 프로그램들을 메인 메모리에 올릴 것인가를 의미한다. 이는 레디 큐에 넣는 것을 의미하며 복수의 프로그램이 선택된다.

 

Short-term scheduler

Short-term 스케줄링(CPU scheduler)은 레디 큐에 있는 프로그램 중 어떤 것을 cpu에서 실행할 것인지 고르는 것을 의미한다.

 

Medium-term scheduler

Medium-term 스케줄링(swapper)은 long-term 스케줄링을 통해 메인메모리에 올라온 프로그램들을 감당하기 어려울 때 그 중에 어떤 프로그램을 메인 메모리에서 내릴지 정하는 스케줄링을 의미한다.

 

그러나 현재의 메인메모리는 가상 메모리를 OS가 제공하기에 메모리는 무한하다고 여기게끔하여 모두 메인메모리에 올라온다. 이에 따라 long term 스케줄링이 없어졌고, medium term 스케줄링도 없어졌다.


 Queueing diagram

프로세스에 대한 정보는 프로세스 컨트롤 블록에 저장되어있는데 이는 큐에 저장이 되어있다가 본인 차례 때 cpu에서 동작한다. 프로세스가 생성된 후 ready가 되니 이때 ready queue에 들어간다. 각 동작에 대해서도 queue에 들어가게 된다. 또한 자신의 타임 퀀텀을 다 쓰면 바로 레디큐로 들어가는 등의 동작을 한다.


Ready queue and various I/O device queues

PCB는 더블리 링크드 리스트로 이를 관리하는데 어느 순간에는 해당 프로세스가 큐에 매달려있다.


HWP & MP4 Player 예시

지금까지 배운 정보를 바탕으로 예시를 풀어보자.

 

백그라운드로 음악을 틀고, 아래한글을 틀어놓는 상황을 가정하자.

 

cpu에서는 운영체제가 수행되다가 HWP가 수행되다가 MP3가 수행되는 식으로 번갈아가며 동작한다. 이때 cpu에서는 하나만 실행되기에 HWP는 running, MP3는 Ready로 가정한다. HWP는 키를 입력받는 것을 기다리는 것이 주 동작이기에 waiting으로 바뀐다. 운영체제는 HWP와 MP3 사이의 컨텍스트 스위칭을 하기에 HWP가 waiting이면 OS가 스케줄링을 한다. 따라서 MP3가 Running 상태로 바뀐다.

 

MP3는 파일 시스템에서 파일을 읽어온 뒤 작업을 한다. 따라서 파일을 읽기 위해 read라는 시스템콜을 해서 운영체제에게 요청을 한다. 따라서 OS가 수행된다. 이때 디스크에게 I/O 명령을 보낸다. MP3는 그 사이에 waiting 상태로 바뀐다. 그러면 HWP와 MP3 둘다 waiting이어서 실행시킬 프로세스가 없게 된다. Cpu는 멈출 수 없기에 운영체제는 idle 프로세스를 하나 만들어서 항상 Ready() 상태로 두다 실행시킬 프로세스가 없으면 실행시킨다. Idle 프로세스는 no operation을 무한 루프로 돌아 실행시킨다. 이에 따라 idle 프로세스가 실행된다.

 

이후 MP3에서 요청한 작업이 완료되어 디스크에서 interrupt한다. 그러면 idle process는 ready 상태가 된다. MP3도 Ready가 된다. 이때 우선순위가 높은 MP3가 running된다. 만약 MP3가 running 중에 HWP에서 키보드를 누르면 키보드 인터럽트가 발생한다. 이에 따라 MP3는 다시 ready 상태가 된다. 이후 HWP도 ready가 된다. 그리고 OS는 스케줄링 알고리즘에 의해 HWP가 실행된다. 이에 따라 HWP는 running 상태가 된다. 운영체제에게 read 시스템콜을 다시 요청하고 키보드 입력을 기다린다. 이에 따라 waiting이 된다. 이후 MP3가 또 ready -> running의 동작을 수행한다.

 

운영체제가 위와 같이 매우 세부적인 단위로 빠르게 수행된다.


 Operation on Processes

프로세스 생성/종료/실행 등등에 관한 함수는 모두 System call에 해당한다.

 

1) 프로세스 생성

(1) fork()

  1. 새로운 PCB를 생성한다.
  2. 프로세스는 메모리에 자리를 잡고 수행되기에 해당 메모리 공간을 잡는다.
  3. new 상태에서 ready 상태로 바꾸고 ready queue에 이를 집어넣는다.

 

fork의 특징

A라는 프로세스를 fork()하면 자기 자신과 똑같은 프로세스를 만든다. 이는 각 각 parent process, child process라고 표현한다. 이러한 경우에는 address space를 똑같이 복사한다.

그리고 실제 메모리 뿐만 아니라 운영체제 안에서 parent process 작업도 똑같이 복사해서 동작할 준비를 한다. 

 

#include <sys/types.h>
#include <unistd.h>

int main() {
	int pid;
    
    if ((pid = fork()) == 0) printf("Child of %d is %d\n", getppid(), getpid()); // child
    else printf("I am %d. My child is %d\n", getpid(), pid); // parent
}

fork를 사용하면 똑같이 복사를 하지만 fork의 리턴 값만 달라진다. 새로 막 생긴 프로세스(child process)는 리턴 값이 0부터 된다. 그런데 원래 main으로부터 시작된 parent process의 리턴 값은 child process의 id(양수)를 가지고 시작한다.

 

cf) ppid는 부모의 프로세스 id이다.

두 개의 프로세스는 동일한 프로그램 코드로 실행된다. 또한 프로세스들은 서로 독립적으로 존재하게 된다.

 

위의 과정을 반복적으로 실행하면 프로세스가 생겼다가 없어지기에 번호가 매번 바뀐다.

 

fork를 하면 child, parent process가 둘 다 ready이다. 이때 누구부터 수행될지는 스케줄링 알고리즘에 따라 정해진다.

 

cf) ./는 현재 디렉토리, a.out은 컴파일 시 실행파일을 지정하지 않으면 디폴트로 정한 실행파일이다.


fork의 장점

parent와의 작업을 할 때 매우 좋다. 대표적으로 아파치라는 이름의 웹서버가 위의 기능을 활용한다. 

 

while (1) {
	int sock = accept();
    if ((pid = fork()) == 0) {
    	// Handle client request
    } else {
    	// Close socket
    }
}

위의 예시는 tcp connection이 맺어지면 child 프로세스를 하나 만들어서 처리하고 parent 프로세스는 반복적으로 listen을 하는 과정을 가진다. 만약 이를 구분하지 않고 계속 parent 프로세스가 모든 사용자에 대해 처리하고자 한다면 한사람 한사람마다 동기적으로 처리해줘야한다. 따라서 위와 같이 parent 프로세스는 각 client를 담당해 처리하도록 하는 구조로 이를 처리할 수 있다.

 

fork를 하는 경우에는 parent 프로세스에 대한 정보를 그대로 가져가기 때문에 parent 프로세스에서 맺었던 연결 설정에 대한 정보를 그대로 가져간다. 따라서 다시 연결설정을 해줄 필요가 없어지게 된다. 따라서 parent와 협력을 맺기가 좋아진다.

 

parent 프로세스의 경우에는 child 프로세스에 이를 복사해줬기 때문에 연결설정을 한 소켓을 사용하지 않을 것이기 때문에 소켓을 닫아준다.

 

cf) 리눅스와 유닉스에서는 위와 같이 하지만 윈도우즈에서는 위와 같이 작업을 하지 않는다.

 


2) 프로세스 실행

(1) exec()

프로그램을 실행시키면 프로세스가 생긴다.  파일 시스템에 있는 실행 파일을 input으로 해서 프로세스를 실행시키는 시스템 콜이 exec이다. 

 

int exec(char *prog, char *argv[])

prog는 프로그램 이름, argv는 아규먼트가 된다. 예를 들어 cp(a, b)를 하는 경우에는 cp라는 파일이 메모리에 올라가고 a, b는 아규먼트로 올라가게 된다. 

 

유닉스, 리눅스에서 exec은 현재 실행 중인 프로세스를 없애고 새로운 프로세스를 넣는다. 유닉스에서는 새로운 프로세스를 실행시킨다면 자기 자신이 없어지기 때문에 fork를 해서 똑같은 프로세스를 만든 뒤, exec을 실행시킨다. 이때 해당 프로세스를 멈추고, 해당 프로세스의 정보를 아규먼트로 전달된 prog의 내용으로 바꾸고, 이후 해당 내용을 실행한다. exec은 새로운 프로세스를 실행되는 것이 아니기에 바로 PCB는 원래 가지고 있던 것을 사용한다. 즉, 메모리를 새롭게 만들 필요는 없다.

 

exec의 리턴값은 이전 프로그램이 된다. 이에 따라 아무런 의미도 없고, return이 된 경우에는 exec이 실패한 경우를 의미한다. exec이 성공한 경우에는 리턴 값이 없다고 가정할 수 있다.

 

 

int main() {

	while (1) {
    	char *cmd = read_command();
    	inf pid;
        if((pid = fork()) == 0) {
        	// Maniuplate stdin/stdout/stderr for pipes and redirections, etc.
            exec(cmd);
            panic("exec failed!");
        } else {
        	wait(pid);
        }
    }
}

사용자의 키보드로부터 라인 하나를 받는 경우에는 read_command를 받는다. 쉘을 실행해주기 위해선 프로세스를 하나 만들어야한다. fork를 통해 자기 자신과 동일한 프로세스를 만든 뒤, 사용자가 친 프로그램을 실행시키기 위해 exec이라는 시스템 콜로 사용자가 타이핑한 커멘드를 실행한다. 

 

cmd라는 커멘드를 성공하게되는 경우에는 해당 프로세스가 성공적으로 만들어졌기에 아래 코드가 진행되지 않지만 만약 리턴이 되고, 아래 코드가 실행된다면 프로세스를 성공적으로 만들었다는 의미가 된다.

 

wait라는 시스템콜은 내가 만든 시스템 콜이 끝나기를 기다리는 상태를 의미한다. 사용자가 커맨드를 주기를 기다렸다가 커맨드를 입력하면 이를 실행시킬 child 프로세스를 만들고 exec을 통해 실행을 시킨 다음, 끝나는 것을 기다리는 과정이 이뤄진다. 끝난 뒤에는 이를 while 문을 통해 반복하게 된다.

 

백그라운드로 실행할 때에는 wait라는 시스템 콜을 실행하지 않아도 된다. foreground를 할 때에는 wait를 하면 된다.


리눅스와 유닉스의 Process Tree

cf) 이는 fork라는 시스템 콜 때문에 그렇다.

 


Process Creation/Execution: Windows

BOOL CreateProcess(char *prog, char *args, ...);

윈도우즈는 모든 프로세스에는 부모/자식 관계가 없이 독립적이게 된다. 윈도우즈는 프로세스를 실행하고 생성하는 것을 createProcess라는 시스템 콜로 제공한다. 파라미터는 exec과 비슷하다. 윈도우즈에서는 새로운 프로세스를 만들고, 새로운 프로세스의 실행을 새로운 프로세스를 만들어서 사용한다. 따라서 parent와 child가 없다.

 

그렇다면 윈도우즈는 tcp/ip에서 클라이언트와 서버의 연결 설정을 어떻게 할까?

윈도우즈는 쓰레드라는 개념이 나온 상황에서 개발된 운영체제이기에 사용자와의 연결은 쓰레드를 통해 관리한다.

 

윈도우즈는 탐색기라는 프로세스를 통해 어떤 프로그램을 실행할 때는 createProcess에서 이를 처리해준다. 유닉스/리눅스 쉘에서는 bash에서 커맨드를 입력하면 bash가 하나 더 만들어지고, 이 bash는 다른 프로그램으로 대체된다. bash는 항상 프로세스가 올라가있는 상태이기에 이 과정이 가능하다.


3) 프로세스 종료

(1) Normal termination

정상적인 프로세스 종료

  • return from main()
  • call exit()
  • call _exit()

cf) _exit()는 일반 어플리케이션에서 호출하는 것을 권장하지 않는다.

 

(2) Abnormal termination

비정상적인 프로세스 종료

  • calling abort()
  • terminated by a signal

 

어플리케이션 프로그램은 abort 시스템콜을 호출해서 비정상적으로 종료할 일이 없기에 실질적으로 쓰이지 않는다. 리눅스/유닉스와 signal은 독립적이다.

 

예를 들어 참조할 수 없는 메모리를 참조하는 경우에는 비정상으로 판단해 운영체제가 해당 프로세스를 abort하는 경우가 많다.

(3) Wait for termination of a child process

  • calling wait()

child 프로세스를 기다리지 않고 parent 프로세스가 동작한다면 다음과 같은 케이스가 등장한다. 

  • parent 프로세스가 wait를 하지 않고 parent 프로세스가 수행 중이다가 child 프로세스가 종료된다면 해당 child 프로세스는 zombie가 된다. 이는 리눅스 버전별로 조금 달라질 수 있다.
  • parent 프로세스가 wait을 수행하지 않고, parent 프로세스가 종료되었다면 child 프로세스는 orphan이 된다.

 

어플리케이션 프로그램이 실행되면 exec이라는 시스템 콜로 실행된다. C start-up routine이 먼저 시작되고, 라이브러리나 링킹 과정을 거친 뒤, main 함수가 호출된다. 이후 main에서 리턴을 하면 C start-up routine이 실행된다. 그리고 C start-up routine에서 exit를 실행한다. main, user function에서도 모두 exit을 할 수 있다. exit에서는 exit handler를 호출하는데, 이는 exit 핸들러를 등록해서 호출한다. 이후 cleanup을 한 뒤, 실제 시스템 콜인 _exit를 실행한다. main이나 사용자 함수에서 _exit을 할 수 있지만 굳이 할 필요는 없다.

 


4) 프로세스 간 협력

(1) Browser Process

사용자 입출력이나 디스크, 네트워크 등 사용자와 I/O 장치를 다루는 프로세스이다. 

 

 (2) Renderer Process

브라우저 창 하나하나마다 Renderer Process가 생성되어 화면에 그리는 역할을 수행한다.

cf) sandbox: 문제가 생기면 해당 프로세스에서만 문제만 생기고 다른 프로세스로 전이되지 않도록 막는다.

 

(3) Plug-in Process

익스플로러는 active x에 디팬던트하게 만들어져서 제한이 있다. 프로세스로 만들어져서 브라우저에 플러그인이 되는 프로세스이다. 

 

사용자 인터페이스, 파일, 네트워크 등에서 읽은 정보를 브라우저 프로세스가 받고, 화면에 보여주기 위해 renderer 프로세스에 이를 보낸다. 즉, 화면에서 보기 위해서는 프로세스 간의 협력이 필요하다.


Multiprocess in Mobile Systems

이전 ios에선 시스템의 성능이나 배터리에 대한 요구사항 때문에 foreground 프로세스를 하나만 허용했었고, 음악을 백그라운드에서 사용할 수 있도록 만들었는데, 지금은 조금씩 풀고 있다. 

 

안드로이드는 백그라운드에서 프로세스를 사용해도 괜찮다. 

 

하나의 프로그램을 만들기 위해 여러 프로세스가 협력하는 일이 필요할 수 있고, 이를 inter process communication(IPC)가 필요하다.


IPC

프로세스 간 협력을 위한 방법

프로세스가 직접 메모리를 사용하는 것은 메모리 보호에 의해 불가능하다. 이를 위해 다음과 같은 방법이 고안된다.

(1) message passing

커널에 message queue를 만들어서 한 프로세스에서 메모리를 저장하고, 다른 프로세스에서 이를 읽어들인다.

 

장단점

  • shared memory 방식에 비해 메모리 복사가 많이 이뤄지기에 성능이 다소 안좋다.
  • shared momory 방식과는 다르게 커널에 내용을 작성하는 것이기에 다른 프로세스가 메모리를 저장했는지 알 수 있다. 이는 커널이 동기화를 알아서 해준다. 만약 메세지 큐가 비어있으면 데이터를 요청한 프로세스는 waiting 상태로 만들고, 기다린다. 그러다가 메세지큐에 내용이 저장되면 자동으로 동기화를 해서 데이터를 가져온다.

 

예시

  • pipes
  • FIFOs
  • Message queue

 

 

(2) shared memory

 프로세스들 간에 공유하는 메모리를 만들고, 프로세스에서 이를 쓰고, 읽는다.

 

 장단점

  •  message passing에 비해 성능이 더 좋다.
  • 메모리를 읽기 전에 프로세스가 해당 메모리에 내용을 썼는지 확인해야한다. 즉, 동기화(싱크로나이즈)가 이뤄져야하기에 이는 어플리케이션이 직접해야한다. 

 

예시

  • Shared memory
  • sockets

 

cf) sockets도 네트워크로 연결된 서로 다른 컴퓨터의 프로세스 간 통신이다.

 


Cooperating processes

Producer

 circular queue에 주기적으로 데이터를 집어넣는 프로세스

 

Consumer

circular queue에 있는 데이터를 가져오는 역할을 한다. 

 

이는 message passing 모델로 할 수 없고, shared memory를 사용할 수 밖에 없다.

 

 

 


Remote Procedure Call(RPC)

(Remote Method Invocation RMI in Java)

일반적으로 함수는 본인 컴퓨터의 함수를 호출하거나 시스템 콜을 하는 방식이 된다. 하지만 함수의 바디가 다른 컴퓨터에 존재할 때 이를 호출하는 경우를 의미한다.해당 함수를 호출할 때는 파라미터가 어떤 것인지 메세지나 패킷으로 정리해야한다. 

 

 


퀴즈를 위한 정리

 

프로그램과 프로세스의 차이에 대해 설명하시오

프로그램은 파일 시스템에 저장된 실행파일을 의미하는 것으로, 이를 실행하면 메모리에 로딩돼서 실행된다. 프로세스는 실질적으로 프로그램을 실행하는 주체가 된다.

 

프로세스 어드레스 스페이스에 대해 설명하시오.

프로세스는 가상메모리를 사용하기에 0번지부터 시작한다. 프로세스 어드레스 스페이스는 text segment, data segment, heap, stack으로 나눌 수 있는데, text segment에는 코드가, data segment에는 static data가, heap에는 동적으로 생성되는 변수, stack에는 함수 호출 시 생성되는 변수들이 저장된다.

 

Scheduler dispatch란?

Ready queue에 있는 프로세스 중 하나를 선택하는 과정을 스케줄링이라 한다. 이후 스케줄된 프로세스를 cpu에 올리는 작업을 디스패치라 한다. 이 과정을 모두 합쳐서 스케줄러 디스패치라 한다. 스케줄러 디스패치를 하면 ready 상태의 어떤 프로세스가 running 상태로 바뀐다.

 

Waiting 상태와 ready 상태의 차이점은?

Waiting은 어떤 작업이 끝날 때까지 프로세스를 동작할 수 없는 상태로, i/o 장치나 event가 모두 수행되기 전까지는 수행되기 어려운 상태이다. Ready는 수행될 수 있는 상태이고 스케줄링이 되기를 기다리는 상태이다.

 

PCB에 대해 설명하시오

PCB는 프로세스에 대한 정보를 가지고 있는 단위를 의미한다. 이는 프로세스가 실행될 때에 대한 cpu 레지스터 정보를 가지게 된다. 이에 따라 프로세스가 스케줄링되면 PCB의 내용을 cpu에 올려 해당 프로세스를 실행시킬 수 있도록 한다. 또한 프로세스 interrupt가 걸리거나 시스템 콜이 요청되면 작업하던 상태를 다시 PCB에 저장하는 식으로 진행된다. 리눅스에서는 task_struct라고 한다.

 

Context switching에 대해 설명하시오


CPU가 한 프로세스를 작업하다가 다른 프로세스를 작업하기 위해 cpu의 상태를 바꾸는 것을 의미한다. 이때 한 프로세스를 작업하는 중에 interrupt나 system call이 발생하면 작업 중인 상태를 pcb에 저장한 뒤, 스케줄된 프로세스를 cpu에 load하고 이를 처리한다.

 

 

Context switching의 단점은?

Context switching은 캐쉬메모리가 매 프로세스가 작업될 때마다 flushing된다는 단점이 있다. 이에 따라 오버헤드가 발생할 수 있다. 하지만 response time 측면에서는 round robin 방식에 의해 훨씬 유리하다.

 

Scheduler의 종류에 대해 설명하시오

Long-term, short-term, medium scheduler가 존재한다. 롱텀 스케줄러는 파일 시스템 중 어떤 프로그램을 ready queue에 넣을 지를 정하는 스케줄러이다. Short term 스케줄러는 레디 큐에 있는 프로그램 중 어떤 것을 cpu에서 실행할지를 정하는 것이다. Medium scheduler는 메인 메모리에 있는 프로그램 중 어떤 프로그램을 내릴지 정하는 스케줄러이다. 현재는 가상 메모리를 OS에서 제공하기에 롱텀, 미디움텀 스케줄러는 사용하지 않고, short term 스케줄러만 사용한다.

 

워드 창과 cd를 틀어놓는 과정을 설명하시오.

우선 워드 프로그램이 running 상태라고 가정을 한다. 워드 프로그램이 running인 경우에 우선 입력을 기다리는 상태가 된다. 그러면 워드 프로그램은 waiting 상태가 된다. 이후 cpu는 음악 프로그램으로 들어가서 디스크에 I/O 명령을 보낸다. 이후 cd도 waiting 상태가 된다. 이때 idle 프로그램이 동작하고 두 프로그램 중 하나가 ready가 될 때까지 기다린다. 디스크에서 정보를 읽어오면 cd의 상태가 waiting에서 ready가 된다. 이후 cd가 스케줄링 디스패치가 되어 cd가 실행된다. 이때 중간에 워드 프로그램에 입력이 들어오면 cd는 interrupt되고, ready 상태가 된다. 이후 워드 프로그램이 running 상태가 되고, 사용자로부터 입력을 받은 뒤, 다시 waiting 상태가 된다. 이후 ready queue에 있는 cd 프로그램이 다시 동작한다. 이런 방식으로 프로그램이 동작한다.

 

리눅스/유닉스 운영체제에서 fork system call에 대해 설명하시오.

Fork는 자기 자신과 똑 같은 프로세스를 만드는 system call이다. 이를 통해 만들어진 프로세스는 child process, 만든 프로세스는 parent process라고 부른다. Child process는 return 값이 0이 된다. 그 외엔 Child process는 parent process의 정보를 모두 갖고 있다. Fork를 하게 되면 parent process와 child process 모두 ready 상태가 된다.

 

리눅스에서 웹서버를 만들 때 사용하는 시스템 콜은?

Fork()를 사용한다. Fork는 자기 자신과 똑 같은 프로세스를 만드는 것을 의미한다. 이를 사용하는 경우에는 parent process는 계속 listen을 하고, child process는 각각 클라이언트에 붙어서 통신을 할 수 있는 과정을 거친다. 이미 parent process에서 연결설정을 했기 때문에 이와 똑 같은 프로세스인 child process에서 통신을 진행하고, parent process에서는 소켓을 닫아주고, 다시 listen을 하게 된다.

 

Exec()는?

Exec() 시스템 콜은 유닉스/리눅스 운영체제에서 사용하는 시스템 콜이다. 파일 시스템에 있는 실행파일을 input으로 하고, 이에 해당하는 아규먼트도 전달해 프로세스를 실행시키는 시스템 콜을 의미한다. 리눅스/유닉스 운영체제에서 Exec()를 사용하면 현재 작업 중인 프로세스를 전달받은 파일로 바꾸기 때문에 fork를 사용한 뒤, exec를 한다. Exec의 리턴값은 의미가 없고, 이것이 리턴되었다는 것은 exec가 실패했다는 것을 의미한다.

 

반면 윈도우에서는 현재 작업 중인 프로세스를 대체하지 않고 독립적으로 프로세스를 생성해 사용할 수 있고, createProcess이라는 이름의 시스템 콜을 사용한다.

 

RPC란? RMI란?

RPC는 다른 컴퓨터에 있는 함수를 호출하는 것을 의미한다. RMI는 자바에서 RPC를 부르는 이름이다.

 

Cooperating process에서 producer와 consumer에 대해 설명하시오

Producer는 circular queue에 주기적으로 데이터를 넣는 프로세스, Consumer는 circular queue에서 주기적으로 데이터를 가져오는 프로세스이다.

 

IPC란?

프로세스 간에 협력을 하기 위한 방법으로 message passing을 하는 방법과 Shared memory를 하는 방식이 있다. Message passing을 하는 방식은 커널에 message queue를 만들어서 데이터를 공유하는 방식이다. Message passing을 하는 경우에는 커널이 알아서 message queue에 데이터가 있는지 확인하기 때문에 데이터가 있는지 점검할 필요가 없지만 메모리 복사가 많이 일어난다는 점 때문에 메모리 부담이 발생한다. 반면 Shared memory 방식은 메모리 부담이 얼마 없지만 데이터가 있는지 없는지는 어플리케이션 단에서 확인해야한다는 단점이 있다.

 

Exit를 할 때 일어나는 동작은?

Exit는 프로세스를 종료시킬 때 사용하는 시스템 콜이다. 사용자 함수나 메인함수 등등에서 exit를 실행할 수 있는데, exit를 호출하면 사전에 정의한 exit handler가 호출된 뒤, 모든 exit handler가 리턴되면 이후에 _exit를 호출하여 끝낸다. _exit 시스템콜은 일반적으로 일반 어플리케이션에서 호출하지 않는다.

 

Abort가 되는 상황은 언제인가?

접근할 수 없는 메모리에 접근을 한다던가 할 때는 비정상적으로 종료하기 위해 abort를 호출한다.

728x90
반응형