본문 바로가기

운영체제/linux

세마포어

1. 인터럽트가 발생해을 때 운영체제의 가장 하위 레벨에서 수행하는 작업의 개요


fork()와 시스템콜로 프로세스가 생성된다. 컴퓨터는 이 프로그램에 대한 정보를 가지게 된다. 프로세스의 생명 주기동안 메모리 영역을 밟게 되는데 그 영역을 주소공간(address space)라고 한다. (memory management)





PC가 어디에 있느냐에 따라 주소 공간의 상태가 계속 변한다. 또한 CPU의 레지스터의 내용도 변하게 된다. (process management)


결국 프로세스의 테이블 정보는 다음을 가지게 된다.


 - memory management

 - process management

 - file management



프로세스가 인생을 살아가면서 그 상태로 (이전의 CPU를 썼던 썼던 상태) 돌아와야 하므로 이전 상태 (PC, 레지스터정보...) 등을 보관하고 있어야 한다.


이런 상태정보를 찍으려면 CPU가 필요하다. 이것을 하는 행위자는 OS이다. 그렇다면?

프로세스의 CPU 상태를 찍으려고 하는데 OS가 그상태를 찍게되면 (OS로 CPU가 돌아오므로...) 결국 자신의 상태를 찍게 된다. 결국 하드웨어가 이 일에 끼어들어 기본적인 일을 대신 수행해주어야 한다.


 - CPU의 기본 정보를 저장한다. (hardware stacks program counter, etc)

 - OS는 그 정보를 가져온다. (hardware loads new program counter from interrupt vector)


그리고 OS는 그런 정보를 읽어서 레지스터를 쓸 수 있게 되므로 OS의 영역이 점점 넓어지게 된다.

(assembly language procedure saves registers.)

(assembly language procedure sets up new stack.)


OS의 인터럽트는 그 프로세스의 CPU의 사용을 중단하게 한다. 인터럽트는 interrupt vector에 따라 대처가 다르다. interrupt가 발생하면 CPU의 상태를 하드웨어에 보관하게 하는 행위도 마찬가지이다. 



2. 프로세스간 통신





스레드는 스택영역을 각각가지고 데이터 영역과 텍스트 영역을 공유한다. 

프로세스간의 통신은 스레드간의 통신이라고도 볼 수 있다.




위는 계좌출금하는 프로그램코드이다. 여기서 문제는 account라는 공유된 변수이다. 각 프로세스는 공통의 account로부터 금액을 출금할 것이다. 이는 스레드가 어느 시점에 중단되느냐에 따라서 남은 잔액이 바뀌게 되는 문제점을 야기한다. 


해결방안은 무엇이 있을까?


1) 임계구역에 들어오면 인터럽트를 꺼버린다.


그럴 경우 임계구역에서 무한루프가 돌 경우 문제가 발생한다.


2) 락변수 사용


락변수도 공유변수이다. 따라서 임계구역에 진입하고 락변수를 바꾸는 사이에 인터럽트가 발생한다면? 문제가 된다. 따라서 락변수를 바꾸는 도중에는 인터럽트를 꺼버려야 한다. (이것은 원자적 연산이다. 시스템이 자체적으로 지원해주기 때문에 건드릴 수 없다.)


3) TSL (test and set lock)


메모리의 어떤 변수를 만들고 테스트 한뒤에 atomic 하게 실행한다.


4) sleep & wake up




자신이 알아서 block된 상태로 이동한다. 하지만 이 또한 문제가 발생한다. sleep 하는 사이에 인터럽트가 발생하면 영원히 잠드는 문제가 발생한다. 



따라서 sleep에 빠지는 과정도 atomic하게 연산해주어야 한다. (한번에 처리)

이것이 바로 세마포어이다. 세마포어를 설명하기 위해 많은 시간이 걸렸다... 

Dijkstra 이 사람은 정말 천재인 것 같다.


세마포어 변수는 어떤 값이 들어갈 수있고 연산도 가능하다. 값은 0부터 int 최대 까지이고 다음의 함수를 사용해 값을 증가, 감소시킬 수 있다


1) P() : 감소

2) V() : 증가


이 연산에는 값이 0이나 최대 일때 sleep 되는 기능과 다른 놈을 깨어주는 기능도 포함되어 있다.


생산자 소비자 문제에서는 세마포어 변수를 3개 사용한다. 


1) mutex


2) empty 


3) full


이때 mutext가 0이면 block 당한다.