PCB
Consists
PCB는 다음과 같이 c의 struct으로 만들어져 있다.
6개로 나눌 수 있다.
- task basic info
- files : 프로세스가 오픈한 파일들의 정보
- fs : 접근중인 파일 정보
- tty : 사용중인 터미널 정보
- mm : 사용중인 메인 메모리 정보
- signals
PCB 구조체에서는 포인터를 이용해서 이들을 6조각으로 나누어 관리한다.
보통 포인터를 사용하는 것은 overhead 문제이다.
Reduce PCB Overhead
- fork를 하는 과정에서 모든 PCB를 복사하는 것은 생각보다 오버헤드가 크다.
read & write
- files, fs, tty, mm, signals 정보는 부모와 다르게 사용되지 않는다.
- 어차피 같은 거면 포인터를 이용해 공유하자!
Linux thread
- 위에서 thread가 사용되었다. thread는 무엇일까?
- 다음과 같이 PCB를 공유하는 자식이지만 모든 PCB를 복사하지 않는 프로세스 상태를 이야기한다.
- 이때는 clone 이라는 시스템 콜이 사용된다.
- 비트를 이용해 복사할 정보를 고를 수 있다.
- clone의 설명은 다음을 참고하자. man clone
여담으로 fork나 clone이나 do_fork로 작동된다 한다.
http://rousalome.egloos.com/9984825
Image overhead
PCB를 복사하는 것 말고도 이미지를 복사할 때 오버헤드가 발생한다.
왜 exec으로 코드를 밀어 버릴꺼면 굳이 fork를 사용할까?
- 이전에는 실제로 그냥 복사하고 밀었었다.
이를 막기위해 page table만 복사하기 시작했다.
그리고 만약 메모리에 write를 한다면 그제서야 그 페이지 부분만 copy 한다.
- 이를 copy on write라고 한다.
하지만 이 방법에는 문제가 있었다.
부모에서 자식으로 넘어가기전 어떤 작업 특히 write를 하게된다면 복사 이전의 메모리 정보가 달라지는 문제가 있다.
- 즉 자식은 이전 상태에서 복사 되었는데(실제 복사는 안됐지만 이론적으로) 자식이 메모리에 접근하기 전 부모에서 메모리를 수정함
그래서 이를 막기 위해 cow작업이 진행된다.
- 허나 자식은 대부분 exec을 진행하기에 의미가 없는 작업이 된다.
해결책
- 그래서 리눅스에서는 이를 해결하기 위해서 fork가 발생하면 바로 cpu를 자식이 먼저 실행되도록 넘겨버린다.
문제점
하지만! 현재는 리눅스에서 실행하면 부모가 먼저 실행된다.
- 직접 코딩해서 확인해보자.
이 부분에 대해 여러 글을 뒤졌지만 완벽한 이유를 찾지 못했다. 뭔가 바뀌긴 했다.
- https://stackoverflow.com/questions/8494732/who-executes-first-after-fork-parent-or-the-child
- 이 글의 마지막 답글을 보면 힌트가 있다.
- 아마도 기본적으로 부모가 실행되고 자식이 실행된다고 생각하기 때문에 이런 직관과 충돌하여 여러 오류를 내는 것 같다.
https://karatus.tistory.com/m/189
- 관련해 정리가 잘된 블로그이다. 하지만 나는 정확한 이유는 이해하지 못했다.
리눅스 쓰레드 모델의 진화
아직은 완벽히 이해하지 못했으나 미래를 위해 삽질한 걸 남겨둔다.
쓰레드 탄생
- 프로세스는 운영체제가 설계될 당시 만들어졌지만 쓰레드는 한참 뒤에 만들어진다.
- 초기에는 작업의 단위가 프로세스 하나였다.
- 이후 cpu가 발전하며, 여러 코어를 가진 cpu가 멀티쓰레드를 지원하기 시작했다.
- 그래서 프로세스를 쪼개어 코어에 배분할 필요가 생겼다.
레벨
- 쓰레드는 유저레벨 쓰레드와 커널 레벨 쓰레드가 존재한다.
유저 레벨
- 운영체제가 멀티쓰레드를 지원하지 않을 때 사용함, 초기 쓰레드 시스템
- 라이브러리를 통해 구현됨
- 커널 쓰레드와 사용자 쓰레드가 1대 N으로 연결된다.
커널 레벨
- 커널이 멀티쓰레드를 지원함
- 1대 1로 연결된다.
멀티 레벨
- M대 N으로 연결된다.
Linux Thread history
- 다음 글을 읽어보자.
리눅스 버전 https://elixir.bootlin.com/
- 2.6 버전으로 크게 바뀐 것 같다.
- 2.6.0 버전에는 남아있었다.
- 2.6.9.rc2 버전에서 사라졌다!