virual memory를 통해 관리
New
: Process가 처음 생성됨.
→ 프로그램이 실행이되면 메모리로 로드가 되고 초기화를 하고 PID를 부여받음, 메모리 구조도 만들어 주고나면 OS가 이를 ready queue에 집어 넣는다
Ready
: 프로세스가 스케쥴러에 의해 선정되어 cpu위에 올라가길 기다린다.
Running
: 프로세스가 할당되어 실행됨.
→ 다른프로세스에 의해 timer interrupt나 인터럽트가 발생하면 현재 프로세스는 ready 상태가 된다.
Waiting
: I/O 요청이나 이벤트에 의해 프로세스가 기다린다.
Terminated
: 프로세스가 실행을 마침.
➔ 각각의 프로세스는 자신의 정보 묶음인 PCB를 가짐.
➔ 많은 정보를 가지고 있어서 생각보다 용량이 크다. Linux2.4기준 1456bytes
➔ 각각의 PCB는 Double Linked List의 형태로 이루어져있다
↪️ 프로세스가 실행되다가 인터럽트가 발생해 운영체제가 개입하여 프로세서에 할당된 프로세스를 바꿀 때 현재 실행되고 있던 프로세스의 진행상황을 PCB의 형태로 메모리에 저장(
register + instruction 값
)한다. 인터럽트에 의해 reload된 프로세스의 이전에 진행상황을 알기 위해서 PCB를 불러와서 실행시킨다
💣 단점
⇒ 그럼에도 불구하고 좋은 방법이라 현재까지 사용되고 있다.
❓ cpu context?
→ 프로세스가 현시점에 어디까지 수행되었는지 register + instruction
프로그램이 바이너리 코드로 형성이 되고 이 바이너리 코드에는 순차적으로 이 프로그램이 어떻게 수행되어야하는지가 명령어의 집합으로 적혀있다. 이 명령어 flow가 현 시점에서 어디까지 수행이 되었는지, 특정 시점에 필요한 레지스터들도 포함해서 context라고 한다.
✅ Batch System
→ CPU utilization↓ (io 끝날 때까지 cpu는 놀아서)
✅ Multiprogramming의 문제
→ 만약에 I/o 없이 동작하는 프로세스의 경우 Process 하나가 cpu 를 독점할 수 있다.
→ 이 문제를 해결하기 위해 timer interuppt를 통해 하나의 프로세스가 사용가능한 max time을 지정해서 fairness를 보장해준다. ⇒ time sharing
Timesharing & Multiprogram
→ interrupt, trap, scheduling을 통해 cpu 위에 올라가는 건 1개의 프로세스이지만 여러개의 프로세스를 왔다갔가 하며 실행할 수 있도록 OS가 관리를 한다.
→ 한정된 메모리에 여러 프로세스를 올려야 하는데 디스크에 저장되어 있는 프로그램 중에서 어떤 것을 ready queue에 넣을 건인지.
→ ready queue에 대기 하고 있는 프로세스 중 어떤 것을 cpu에 올려줄 것인가
→ 메모리가 부족해졌을 때 어떤 프로세스를 다시 디스크로 내릴 것인가
fork()
: 수행 중이던 프로세스가 새로운 프로세스를 만드는 것은 운체에게 요청exec()
: 새롭게 프로세스가 만들어짐. 이 상태에서 디스크에 있는 아직 프로세스가 되지 못한 프로그램을 수행시키위해서는 프로세스 형태를 갖추야 하는데 기존의 프로세스에 실행되어야 하는 프로그램의 내용을 덮어씌워서 실행시킴 fork된 프로세스 위에 새로운 프로그램 덮어서 사용exit()
: 사후처리를 하고 프로세스를 종료시켜라 (버터플로싱, 아이오버퍼 없애기, dll 해제, 메모리 맵 할당 해제 원래 운체꺼니까)_exit()
: 사후처리 없이 종료 시키키 → 쓸 일이 거의 없다.abort()
: 비정상 종료가 일어나는 경우에 사용 그 로그 정보를 리포팅해줄 수 있는 것.wait()
: 멀티 프로세싱으로 프로그램이 동작이 될 때 부모자식관계에서 부모가 자식이 동작이 끝날 때까지 기다려라📌 fork()
- 새 PCB를 만들고 초기화된다
- 새 memory address space가 만들어지고 초기화된다.
- parent의 address space전체를 copy
- child의 PCB를 ready queue에 넣는다.
fork()
의 return값으로
- Parent process에게는 child peocess의 pid를 return
- Child process에게는 0을 return
fork
#include <sys/types.h>
#include <unistd.h>
int main()
{
int pid;
if ((pid = fork()) == 0)
/* child */
printf (“Child of %d is %d\n”, getppid(), getpid());
else
/* parent */
printf (“I am %d. My child is %d\n”, getpid(), pid);
}
getppid
→ 내 부모의 pib값을 가져옴getpid
→ 내 pib값↪️ 결과
% ./a.out
I am 31098. My child is 31099.
Child of 31098 is 31099.
% ./a.out
Child of 31100 is 31101.
I am 31100. My child is 31101.
⇒ 스케쥴러에 의해 패러트가 먼저 자식이 먼저 수행될 수도 있기 때문에 순서가 뒤바뀔 수 있다. pib값도 매번 실핼시킬 때마다 다르 수 있다
💁🏻♀️ 그래서 folk 어디에 쓸까?
부모와 새로 생성된 자식 프로세스가 협력해야할 때
ex) web server
ex) 네이버 서버 → 싱클 패스 → 망함 : 검색을 했는데 서버가 계속 리스닝하다가 요청이 오면 검색어로 검색 엔진을 돌리는 동안 다른 원격 사용자가 리퀘스트를 보내면 리스닝을 안하고 있으니가 메세지가 discard됨.
아팟치의 코드
While (1) {
int sock = accept();
if ((pid = fork()) == 0) {
/* Handle client request - */
} else {
/* Close socket - 부모는 소켓을 닫거나 리스닝 하거나*/
}
}
exec()
int exec (char *prog, char *argv[])
: 보통 fork랑 같이 수행이 된다. 새로운 프로그램을 프로세스 형태로 실행시켜주는 system call
⇒ child가 더 이상 부모와 같은 형태가 아니라 다른 역할을 하게 되다
✔ [ 진행 과정 ]
현재 실행 중이 프로세스를 멈춘다
prog에 명시되어 있는 프로그램을 exec
을 수행한 프로세스의 memory address space에 로드한다.
HW context, argv를 초기화
PCB를 ready queue에 올린다
새로운 process를 만드는 것이 아니라 exec을 호출하고 있는 프로세스에 새 프로그램을 덮어써서 사용 ⇒ 그래서 보통 fork and exec
이라고 한다.
현재 아직 실행되지 않은 것을 뒤집어 씌워서 부모와는 전혀 다른 새로운 것이 됨
→ 실행가능한 바이너리 이미지를 메모리에 로드 (덮어쓰기) → 그 프로그램을 실행할 때 필요한 하드웨어 리소스 초기화 → … → PCB 정보도 지금 실행하고 있는 것으로 완전히 바뀜 → PCB를 ready queue에 넣는다.
int main()
{
while (1) {
char *cmd = read_command();
int pid;
if ((pid = fork()) == 0) {
/* Manipulate stdin/stdout/stderr for
pipes and redirections, etc. */
exec(cmd);
panic(“exec failed!”);
} else {
wait (pid);
}
}
}
pid =0 —> idle process
CreateProcess()
—> folk + exec
—> system call이 다르기 때문에 window의 프로그램은 unix 계열에서 안돌아간다. 반대도 마찬가자지!
exit()
함수에서 → 마지막에서 _exit가 호출됨_exit()
쓸일 이 없다2. Abnormal termination : 비정상
abort()
: 사후처리 핸들링 다 해주고 어떠한 비정상적으로 인해 종료 되었는디 로그 남겨주기3. Wait for termination of a child process
wait()
: 자식 프로세스가 끝날 때 까지 부모 프로세스가 기다리는 경우 (동기화를 맞추기 위해) , 자식 프로세스가 종료가 될 때 자식 프로세스가 가지고 있는 여러 리소스들에 대한 정리가 필요한데 이런 것들이 부모 프로세스를 통해 ~~ 만약 부모가 종료되지 않고 살아있는데 wait호출을 안하면, 자식 입장에서 보고할 곳이 없어지는 것. —> zombie processzombie
→ 부모 프로세스가 살아있긴 한데 wait 호출을 안해서 둥둥 떠다니는 경우orphan
: 고아■ Google Chrome Browser is multiprocess with 3 different types of processes:
Browser process
: user interface, disk and network I/O를 담당Renderer process
renders web pages, deals with HTML, JavascriptPlug-in process
for each type of plug-in✔ https → 보안성을 강화한 형태
✔ 샌드박스 : 격리된 환경, 이곳에서 보안문제가 있는지 미리 돌려보고 확인하기
■ Some mobile systems (e.g., early version of iOS) allow only one process to run, others suspended
■ Due to screen real estate, user interface limits iOS provides for a
■ Android runs foreground and background, with fewer limits
💁🏻♀️ 역사
✅ ios
→ ios라 불리기 이전에는 멀티프로세싱이 안 되었다.
→ 사람들의 요구로 인해 멀피트로세싱이 지원, 하지만 제한적이다.
→ 모바일 디바이스와 관련되어 있는 분야에서 보안 킹임. 애플이 내는 화이트해커 내용이 거의 백서임
→ ios는 기반이 next step의 커널을 쓴다.
✅ android
→ 반면 태생이 리눅스 커널이라 처음부터 멀티프로세싱이 지원이 되었다. 그러나 느리고 리소스가 많이 필요했다
→ 상대적으로 멀티 프로세싱이 잘 되며 자유도가 높다 → 보안이 취약하다
= ✉️ 메모리 패싱은 우편이다.
커널에서 버퍼를 만듬, 여기에 접근할 수 있는 녀석이 프로세스 에이 비다 지정
✅ 단점
✅ 장점
= 📋 shared memory는 게시판이다
💭 Process B가 A한테 무언가 전달하고 싶을 때…
→ 커널에게 요청, 나한테 에이와 비가 동시에 접근해도 괜찮은 메모리 영역을 할달 해줘
→ 커널이 그래 잘 쓰고 반납해라 하고 shared memory 할당
→ 개발자 입장에서 비가 에이한테 뭔가 전달하려고 할 때 에이가 비가 공유된 곳에 무언가를 넣은 것을 알 수가없다. 그래서 그런 메커니즘을 모두 개발자가 신경써야 함.
✅ 장점
✅ 단점
■ Cooperating processes
Bounded buffer problem
(Producer-Consumer problem) 협력하는 프로세스 중 정보를 생산하는 프로세스를 생산자(Producer), 정보를 소비하는 프로세스를 소비자(Consumer)라고 부른다. 생산자-소비자 문제는 두 프로세스가 동시에 동작할 때 일어나는 이슈 를 말한다. 보통 정보가 생산되는 속도가 소비하는 속도보다 빠르기 때문에 동기화 문제가 발생하는데, 이를 해결하기 위해 생산된 데이터를 담아두는 버퍼(Buffer)를 사용한다.