공부함

Process Management 본문

운영체제/이화여대 강의

Process Management

찌땀 2023. 10. 16. 15:32

https://core.ewha.ac.kr/publicview/C0101020140321144554159683?vmode=f 

 

반효경 [운영체제] 8. Process Management 1

설명이 없습니다.

core.ewha.ac.kr

 

프로세스 생성 

- 부모 프로세스가 복제해서 자식 프로세스 생성 

- 복제 : 프로세스의 문맥을 모두 복사한다

  - 주소공간 code, data, stack 

  - cpu 문맥 : pc 레지스터 

- 부모 프로세스 하나가 자식을 여럿 생성한다 -> 프로세스의 트리 구조 생성 

- 프로세스가 실행되기 위해서는 자원을 필요로 함

✔ 자원은 운영체제로부터 받는다 

✔ 부모 프로세스와 자원을 공유하는 모델도, 안하는 모델도 있다. (원칙적으로는 공유하지 않음)

리눅스, 일부 운영체제에서는 모든걸 copy하지 않고 공유할 수 있는 것은 공유하려고 한다. (효율성을 위해)

pc만 하나 copy해서 같은 곳을 가리키고 있는 상태가 됨 

그러다가 부모와 자식이 달라지게 되면 그 때 부모의 메모리공간 일부를 copy해서 자식이 갖게 한다 

이것을 copy-on-write = COW 기법이라고 한다. = write가 발생 했을 때 copy를 하겠다.

write가 발생 -> 원래 있던 내용을 바꿈 

그 이전까지는 부모의 내용을 그대로 공유한다

✔ 자식 프로세스는 부모 프로세스와 별도의 프로세스. 일반적으로는 경쟁관계(CPU와 메모리)가 된다.  

- 수행 

✔ 부모와 자식이 공존하며 수행하는 모델 

✔ 자식이 종료될 때 까지 부모가 기다리는(blocked) 모델 

 

자식 프로세스는 어떻게 부모 프로세스를 복제해서 생성하는가?

- 주소공간

✔ 부모 프로세스의 주소 공간을 자식 프로세스가 복제 

✔ OS에 있는 데이터(PCB, 자원 등)도 똑같이 복사 

✔ 일단 복제하고, 복제된 공간에 새로운 프로그램을 덮어 씌울 수 있다

- 유닉스의 경우 ..

✔ fork() 시스템 콜을 통해 부모 복사 

✔ 주소 공간 할당 

✔ exec() 시스템 콜을 통해 새로운 프로그램을 메모리에 올림 

즉, 부모 프로그램을 복제, 새로운 프로그램을 덮어 씌우는 2단계로 프로세스의 생성이 이루어진다 

fork()와 exec()은 완전히 개별적인 것으로 둘중 하나만 할 수도 있다.

fork()만 해서 복제만 해놓을 수도 있고,

exec()만 해서 프로그램을 덮어 씌워서 새로운 프로세스로 바뀔 수도 있다. 

 

사용자 프로세스가 직접 다른 프로세스를 생성하는 것은 아니고, 운영체제를 통해서만, 즉 fork, exec 같은 system call을 통해서만 생성이 가능하다. 

 

프로세스 종료 

- 프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려줌 : exit() 시스템 콜

✔ exit 시스템 콜은 자발적으로 프로세스가 종료되는 경우다

✔ 프로세스를 종료 할 때는 자식이 부모에게 output data를 보낸다. wait() 시스템 콜 

✔ 프로세스의 세계에서는 항상 자식이 먼저 죽는다 

- 비자발적으로 프로세스가 종료되는 경우도 있다. 부모 프로세스가 자식 프로세스의 수행을 종료시킨다 : abort

✔ 자식이 할당 자원의 한계치를 넘어섬 

✔ 자식에게 시킬 일이 더이상 없음 (할당된 태스크가 더이상 필요하지 않음)

✔ 부모 프로세스가 종료(exit)되는 경우 

부모를 종료해야 하기 때문에 모든 자식 프로세스를 죽인 후에 본인이 죽는다 

단계적인 종료(손주 -> 자식 -> 부모)

 

fork() 시스템 콜

fork를 사용해서 사용자 프로그램이 어떻게 프로세스를 만드는가? 

fork()가 운영체제에게 새로운 프로세스를 만들어 달라는 시스템 콜이다. 

자식 프로세스는 fork() 이후부터 실행하게 된다.

왜냐? 부모 프로세스의 문맥을 복사해 와서 pc 값이 fork 이후를 가리키고 있기 때문! 

 

복제를 통해 자식 프로세스를 생성하면 두가지 문제점이 있다 

  • 자식 프로세스도 부모랑 똑같이 생겨서 자신이 원본이라고 주장함 
  • 모든 프로세스의 제어 흐름이 같아짐 

이러한 문제를 막기 위해 복제를 할 때는 자식하고 부모를 구분한다. 

fork 함수의 반환값인 pid로 구분한다. 

부모 프로세스는 pid > 0이고 (자식 프로세스의 주민번호)

자식 프로세스는 pid == 0이다. 

fork의 반환값이 다르기 때문에 부모 프로세스와 자식 프로세스는 다른 일을 하도록 할 수 있다. 

 

하지만 제어 흐름 상에서 다른 제어 흐름을 갖는 것이지 전체 코드는 결국 같다. 

 

exec() 시스템 콜 

이를 해결하기 위해 존재하는 것이 exec()이다

프로그램을 완전히 새로운 프로세스로 태어나게 해 준다.

execlp()가 exec() 시스템 콜을 하는 함수다.

프로그램 이름을 첫번째, 두번쨰 인자로 전달하고 argument를 세번째 인자부터 나열해서 전달한다.

마지막에는 (char *)0 를 적어준다.  

새로운 프로그램으로 덮어 씌운다. 

새로운 프로그램의 시작 부분부터(main) 실행하게 된다. 

/bin/date 라는 프로그램을 실행한다. 

date를 실행하고 나서. 한번 exec 하게 되면 되돌아올 수 없다.

따라서 exec 뒤의 코드는 영원히 실행할 수 없는 코드가 된다. 

exec은 꼭 자식을 만들어서 해야 하는 것은 아니다.

fork를 안하고 exec을 할 수도 있다. 

 

wait() 시스템 콜 

wait 시스템 콜은 프로세스를 block 상태로 만드는 것이다 

block 상태 : CPU를 줘도 instruction을 수행할 수 없는 상태 (CPU를 얻지 못함)

 

보통 자식 프로세스를 만든 다음에 wait 시스템 콜을 한다 

프로세스 A가 wait 시스템 콜을 호출하면 자식  프로세스가 종료되기를 기다리며 blocked 상태가 된다 

자식 프로세스가 종료되면 프로세스 A가 blocked에서 ready 상태가 된다. 

ready 상태 : CPU를 기다리는 상태 (메모리 등 다른 조건은 모두 만족한 채로)

 

즉 이 경우는 자식을 낳아놓고 부모가 자식을 기다리는 모델이 되겠다.

 

대표적인 예시로 LINUX의 쉘이 있다. 

쉘에 프로그램 명을 입력해서 실행하면 자식 프로세스 형태로 생성되고,

그동안 쉘은 wait을 호출해 blocked로 기다리게 된다. 

 

exit() 시스템 콜 

명시적으로 exit을 호출해 프로그램을 끝낼 수도 있고, 

보통은 프로그램이 끝나는 시점에 컴파일러가 exit 시스템 콜이 호출되도록 한다 

 

보통 자발적 종료일 때 exit을 통해 종료가 된다. 

 

비자발적 종료일때는 프로그램은 코드를 실행하고 있는데 외부에서 프로그램을 죽여버리는 것이다. 

  • 부모 프로세스가 자식 프로세스를 죽임 
    • 자식 프로세스가 한계치를 넘는 자원 요청 
    • 자식에게 할당된 태스크가 더이상 필요하지 않음
  • 사람이 키보드로 kill, break를 입력한 경우 
  • 부모 프로세스가 종료되는 경우
    • 부모 프로세스가 종료하기 전 자식 프로세스가 먼저 종료된다 
    • 계층적으로 프로세스가 죽는다

프로세스와 관련된 시스템 콜 4가지를 정리해보자 

  • 부모 프로세스를 복제 생성하는 fork 
  • 새로운 프로그램으로 덮어 씌우는 exec 
  • 자식 프로세스가 종료될 때 까지 blocked 상태가 되는 wait
  • 모든 자원을 반납하고 프로세스를 종료하는(부모에게 죽는다고 알림) exit 

 

프로세스 간 협력 

  • 독립적 프로세스 
    • 일반적으로 프로세스는 독립적이다. 
    • 각자의 주소 공간을 갖고 수행된다 
    • 경쟁
    • 하나의 프로세스는 다른 프로세스의 수행에 영향을 미치지 못한다 
  • 협력 프로세스 
    • 경우에 따라서는 프로세스간 협력을 해야 효율적인 경우가 있다. 
    • 프로세스간에 정보를 주고받는 협력 메커니즘 = IPC : InterProcess Communication 
      • IPC를 통해 하나의 프로세스가 다른 프로세스의 수행에 영향을 미칠 수 있다 
      • IPC에는 크게 2가지 방법이 있다
        • message passing : 메세지를 전달하는 방법 
          • 프로세스 A가 프로세스 B에게 메세지를 전달하고 그 영향을 받아서 프로세스 B가 실행된다 
          • 프로세스는 자신의 주소공간만 볼 수 있다. 따라서 커널을 통해서 메세지를 전달한다 
          • 프로세스 사이의 공유 변수를 일체 사용하지 않고 통신하는 시스템이다 
          • Message Passing도 두가지로 나뉜다 
            • Direct Communication : 통신하려는 프로세스 이름을 명시 : Send(Q, message)
            • Indirect Communication : mailbox 또는 port를 통해 메세지 간접 전달 Send(M, message)
              (M은 mailbox), 우체통에 메세지를 집어놓고 아무나 꺼내가라는 식으로 할 수도 있다
              mailbox는 kernel에 있다 
            • 두 방법 모두 OS(kernel)을 통해 메세지를 전달한다는 점은 같다 
            • 사용자 프로세스끼리 직접 무언가를 전달하는 것은 불가능하다 
        • shared memory : 주소 공간을 공유하는 방법  
          • 원칙적으로 프로세스는 자기 주소공간만 볼 수 있다 
          • 일부 주소공간을 두 프로세스가 공유하는 방법이 shared memory이다 
          • Shared Memory를 하려면 커널에게 system call을 해서 mapping을 해놓고 share 를 하게 한 다음에 사용자 프로세스 끼리 영역을 공유할 수 있는 것이다. 
          • 즉 처음에는 커널에게 도움을 받지만, 그 이후부터는 사용자 프로세스 끼리 작업을 할 수 있다 
          • 둘이서 점잖게.. 잘 써야 한다 (잘못된 결과가 나올 수 있다)
          • 서로 신뢰할 수 있는 프로세스 끼리 헤야 함! 

Shaed Memory 방식에서는 Process A와 Process B의 주소공간을 물리적인 메모리에 매핑할 때 일부 공간이 공유되도록 한다

 

thread 

스레드는 프로세스 하나 안에 CPU 수행 단위가 여러개 있는 것

프로세스 간 협력은 아니다. 

스레드들 끼리는 주소공간을 완전히 공유한다. 

따라서 스레드 간 완전한 협력이 가능하다 

 

 

'운영체제 > 이화여대 강의' 카테고리의 다른 글

DeadLock  (9) 2023.11.10
Process Synchronization  (0) 2023.10.17
CPU scheduling  (0) 2023.10.16
Process  (0) 2023.10.10
운영체제란 무엇인가, 시스템 구조와 프로그램 실행  (0) 2023.10.10