26 - threads intro

쓰레드 간의 문맥 교환 (context switching) 은 running thread가 사용하던 레지스터들을 저장하고 ready thread가 사용하던 레지스터의 내용으로 복원한다는 점에서 프로세스의 문맥 교환과 유사하다.

프로세스가 문맥 교환을 할 때에 프로세스의 상태를 프로세스 제어 블럭(process control block, PCB)에 저장하듯이 프로세스의 쓰레드들의 상태를 저장하기 위해서는 쓰레드 제어 블럭(thread control block, TCB)이 필요하다.

가장 큰 차이 중 하나는 프로세스의 경우와 달리 쓰레드 간의 문맥 교환에서는 주소 공간을 그대로 사용한다는 것이다 (사용하고 있던 페이지 테이블을 그대로 사용하면 된다).

멀티 쓰레드 프로세스의 경우에는 각 쓰레드가 독립적으로 실행되며 쓰레드가 실행하기 위해 여러 루틴들을 호출할 수 있다. 주소 공간에는 하나의 스택이 아니라 쓰레드마다 스택이 할당되어 있다. -> thread local storage라고 불림

어떤 쓰레드가 언제 실행되는지 알기 어렵다

명령어의 실행 순서에 따라 결과가 달라지는 상황을 경쟁 조건 (race condition) 이라고 부른다.

멀티 쓰레드가 같은 코드를 실행할 때 경쟁 조건이 발생하기 때문에 이러한 코드 부분을 임계 영역(critical section)이라고 부른다. 공유 변수 (또는 더 일반적으로는 공유 자원)를 접근하고 하나 이상의 쓰레드에서 동시에 실행되면 안 되는 코드를 임계 영역이라 부른다.

이러한 코드에서 필요한 것은 상호 배제(mutual exclusion)이다. 이 속성은 하나의 쓰레드가 임계 영역 내의 코드를 실행 중일 때는 다른 쓰레드가 실행할 수 없도록 보장해준다.


27 - threads api

<aside> 💡 핵심 질문 : 쓰레드를 생성하고 제어하는 방법 운영체제가 쓰레드를 생성하고 제어하는 데 어떤 인터페이스를 제공해야 할까? 어떻게 이 인터페이스를 설계해야 쉽고 유용하게 사용할 수 있을까?

</aside>

int pthread_create( pthread_t * thread,
	 // 쓰레드의 속성을 지정하는 데 사용. 스택의 크가와 쓰레드의 스케줄링
   // 우선순위 같은 정보를 지정하기 위해 사용될 수 있음.
	 const pthread_attr_t * attr,
	 // 이 쓰레드가 실행할 함수 포인터
	 void * (*start_routine)(void*) , 
	 // void *를 사용하면 어떤 데이터 타입도 가능, struct도
   void * arg
); 

do_fork 에서 sema up_ sema down