스케줄러 : 하드웨어 관리를 진행하는 운영체제 코드의 일부.
Swap out: 메모리를 통째로 뺴앗겨 디스크로 쫓겨나는 것
Swap in: 메모리를 다시 얻어 메모리 상에 올라가는 것
만약 브라우저를 여러개 띄운다.
-> 각각이 동일한 여러 개의 프로세스가 생성
-> 코드 - 데이터 - 스택 공간 중 중복되는 부분이 생겨나 비효율적.(같은 코드를 실행하는데 프로세스 별로 데이터, 스택값은 다를 것이기 때문)
각각을 다 프로세스로 만들지 않고, 쓰레드로 두자.
동일한 프로그램을 여러개 띄우더라도, 하나의 프로세스가 만들어진다.
각각 띄워진 프로그램들은 각기의 코드 흐름을 수행
-> PC(코드의 어느 부분을 수행하고 있는가)를 쓰레드 별로 나누어 각각 존재하게끔 함.
-> 코드 흐름에 따라 스택에 생겨나는 데이터들이 별도로 쌓이게 될 것.
효율적으로 처리가 가능하고, 프로세스A에서 B로 넘어가는 context switch의 오버헤드가 없어짐
쓰레드1 -> 쓰레드2 로 CPU가 넘어가는 것이 부담이 적다.
하나의 프로그램을 다중 쓰레드를 통해 구현하면 훨씬 효율적이다.
"A thread (or lightweight process) is a basic unit of CPU utilization."
Thread 구성
: Program counter, register set, stack space
Thread가 동료 thread와 공유하는 부분(= task). 자원 배분의 입장에서 경제적임.
: code section, data section, OS resources
전통적인 개념의 "Heavyweight process"는 하나의 스레드를 가지고 있는 task로 볼 수 있다.(1 process 1 thread)
다중 스레드로 구성된 테스크 구조에서는 하나의 서버 스레드가 blocked(waiting) 상태인 동안에도 동일한 테스크 내의 다른 스레드가 실행(running)되어 빠른 처리를 할 수 있다.
: 스레드가 하나 있을때는 I/O 시 CPU를 빼앗긴다. (당장 할 일이 없으니까)
이게 좀 비효율적인게, 예를 들어 웹 브라우저에서 포털 사이트에 접근한다고 할 때 네트워크로부터 웹페이지 내용을 읽어온다.(일종의 I/O 작업). 그동안 웹브라우저에 CPU를 안주게되면 아무 화면도 안뜨고 기다려야할 것.
하지만 쓰레드를 활용하여 하나의 쓰레드가 I/O 읽어오기 작업을 진행하고 다른 쓰레드는 띄워줄 수 있는 데이터(먼저 읽어온 데이터)들을 먼저 화면에 보여주게되면 사용자가 덜 답답하게 느낄 수 있다.
동일한 일을 수행하는 다중 스레드가 협력하여 높은 처리율(throughput)과 성능 향상을 얻을 수 있다.
스레드를 사용하면 병렬성, 응답성을 높일 수 있다.
스레드를 이용한다면 Multiprocess 구조에서 병렬성을 활용하여 효율적이고 빠르게 연산처리가 가능하다.
쓰레드를 구현하는 방법
1. 운영체제가 스레드에 대해 알고 있는 경우 -> Kernel Threads
: 운영체제가 쓰레드 별로 CPU를 배분 (ex: Windows 95/98 ... , Solaris, Digital UNIX 등)
2. 운영체제가 스레드에 대해 모르는 경우. 프로세스 내부에서 스레드 관리를 한다. -> User Threads
: 사용자 프로그램 단에서 쓰레드를 관리 (ex: POSIX Pthreads, Mach C-threads 등)
: 부모 프로세스가 자식 프로세스를 복제 생성(Parent -> children)
운영체제에 시스템콜을 통해 자식을 만들어달라고 요청(fork())
생성된 자식은 별개의 프로세스이기에 각자 수행됨.
프로세스의 트리 계층 구조 형성
프로세스는 자원을 필요로 함
운영체제로부터 받는다.
부모와 공유한다.
자원의 공유
부모와 자식이 모든 자원을 공유하는 모델
일부를 공유하는 모델
전혀 공유하지 않는 모델
수행 (Execution)
부모와 자식은 공존하며 수행되는 모델
자식이 종료(Terminate)될 때까지 부모가 기다리는(wait) 모델 -> Blocked 상태
주소 공간 (Address space)
자식은 부모의 공간을 그대로 복사함(Binary and OS data)
자식은 그 공간에 새로운 프로그램을 올림
유닉스의 예
fork()시스템 콜이 새로운 프로세스를 생성
-> 부모를 그대로 복사(OS data except PID + binary)
-> 주소 공간 할당
fork() 다음에 이어지는 exec() 시스템 콜을 통해 새로운 프로그램을 덮어씌워 메모리에 올림.
fork()시, 부모 프로세스는 해당 함수의 결과값으로 자식의 PID를 받게됨. 자식은 0을 받게됨.
즉 fork()의 결과값을 통해 부모 / 자식을 구분할 수 있다.
만약 복제생성한 자식이 다른 일을 하게 해주려면? -> exec() system call 활용
exec() 사용 시 해당 프로세스가 실행하고자 하는 프로세스로 완전히 덮어씌워지게 된다.
프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려줌 (exit() 시스템 콜)
자식이 부모에게 종료된다는 output data를 보냄 (via wait).
프로세스의 각종 자원들이 운영체제에게 반납됨.
부모 프로세스가 자식의 수행을 종료시킴 (abort)
자식이 할당 자원의 한계치를 넘어섬
자식에게 할당된 테스크가 더이상 필요하지 않음
부모가 종료(exit())하는 경우
-> 운영체제는 부모 프로세스가 종료하는 경우 자식이 더 이상 수행되도록 두지 않음.
-> 단계적인 종료(프로세스의 계층에 따라 하위층부터 정리)
철학자 과제를 통해 얻었던 지식들이 새록새록 생각나네요!