티스토리 뷰

비동기적으로 생산되는 여러 프로세스들을 동기화 시켜주기 위한 도구로 세마포어를 사용한다.


즉, 어떤 문에 입장할수 있는 인원은 한명인데 여러명이 입구에서 대기를 하는 와중에 통제하는 사람이 한명씩만 입장 시키는 상황이다.


그 역할을 하는게 세마포어이다. 신호등 or 신호기 라는 뜻을 가지고 있다고 한다.


세마포어는 int,char처럼 어떤 한 자료형이고 추상적이다.


세마포어는 down,up이라는 두 연산을 통해서만 값을 변경할 수 있다.


세마포어는 커널에 저장된 변수이며, 시스템콜(down,up)을 통해서만 값을 수정할수있다.


down

-> 세마포어 값이 0이면 프로세스를 블락시킨다(잠들게 한다)

-> 그렇지 않으면 값만 감소시키고 하던일 그대로 진행시킨다.

up

-> 블락된 프로세스가 있다면 그 프로세스를 깨우고 실행되지 못한 나머지 부분을 마저 실행시킨다.

-> 블락된 프로세스가 없다면 그냥 값만 증가시킨다.


down과 up연산은 쪼개질수 없는 원자적 단위이다. 다시 말해서 down&up 연산을 수행 하는 도중에 스케쥴링이 일어날수 없게끔 되어있다.


up과 down은 커널이 제공하는 시스템 콜이며, 이 연산을 수행하는 도중에 인터럽트가 걸리지 않게끔 설계되어 있다.


세마포어를 사용하면 생산자 소비자 문제에서 경쟁 상태에 놓이는것을 방지 할 수있다.


생산자 소비자 문제에서 경쟁상태가 발생하는 이유는 프로세스간 상호배제를 구현하지 못했기 때문이다.


생산자가 공유변수에 접근하고 동시에 소비자가 공유변수에 접근했기 때문에 발생한 문제인데


세마포어를 사용하면 그것을 방지 할 수 있다.


이진 세마포어란 0과 1의 값만 가질 수 있는 추상적인 자료형이다.

mutex라고 불린다. (mutual + exclusion)


mutex는 상호배제 기능을 제공해준다.


또한 버퍼가 비었을때 소비자는 잠들어야 하고 버퍼가 꽉찼을때 생산자는 잠들어야 한다.

이런 동기화문제를 해결해 주는것이 full이라는 세마포어와 empty라는 세마포어이다.


이 2개의 세마포어는 버퍼가 꽉 차면 생산자가 잠들고 버퍼가 비면 소비자가 잠드는것을 확실하게 보장해준다.




위의 코드를 보면 여러개의 세마포어가 나온다. 이진 세마포어(뮤텍스 세마포어로도 불림,mutex)1개와 카운팅 세마포어(empty,full)2개가 나타난다. 왜 두개의 함수를 멀티쓰레딩 환경에서 실행시키기 위해서 3개의 세마포어나 필요한지 살펴보자.

그전에 카운팅 세마포어라는것이 무엇인지 보자.  쉽게 생각해서 카운팅 세마포어는 그냥 카운팅 변수로 보면 된다. 예를들어 공유 자원의 개수가 4개 있다고 하면 처음에 empty의 값은 4일것이고 full은 0일것이다. 공유 자원을 접시로 생각해보자. 생산자는 그 접시에 빵을 생산하고 소비자는 접시에 있는 그 빵을 먹는 역할을 한다.


생산자와 소비자가 동시에 공유 자원에 접근해야 하기 때문에 빵이 있는 상태에서만 소비자가 접근해야 하고 빵이 가득차있는 상태에서는 생산자는 더이상 공유 자원에 접근하면 안된다. 그러기 위해서 빵 하나를 생산, 소비 할때마다 빈 접시, 빵 접시의 개수를 카운팅 해야 한다. 그 역할을 하는것이 카운팅 세마포어이다. 즉, 쓰레드가 동시에 접시라는 공유자원에 접근하게 되는데, 접근 할 수 있을때만 접근하게 만들어야 한다. 그렇기 때문에 생산자 코드에서 맨처음에 down(&empty)이 있는것이고 소비자 코드에서 맨처음에 down(&full)을 실행 하는것이다. 생산자는 빈접시를 없애는  역할을 하고, 소비자는 빵이 올라간 접시를 없애는 역할을 하기 때문이다.


카운팅 세마포어(full,empty)를 사용해서 소비자 함수 생산자 함수에서 각각 돌아가는 쓰레드들이 들어갈수있을때만 들어가게 만들었다. 그럼 끝일까? 그냥 이상태에서 위의 두 함수를 멀티 쓰레딩으로 실행시키면 레이스 컨디션이 발생한다. 왜냐면, 서로 다른 쓰레드가 공유 자원에 동시에 접근했기 때문이다. 그렇기 때문에 카운팅 세마포어 안에 이진 세마포어로 한번더 감싼것이다. 멀티 쓰레딩 환경에서는 기본적으로 이진 세마포어는 무조건 사용된다고 보면 된다. 공유 자원에 접근하는 코드 부분인 크리티컬 섹션에서는 무조건 한번에 하나의 쓰레드만 입장 해야 한다. 만약 생산자 함수에서만 멀티쓰레드로 돌아간다고 했다면 카운팅 세마포어는 굳이 필요하지 않았을것이다. 하지만, 여러개의 쓰레드가 서로 다른 함수에서 각각 동시에 실행 되기 때문에 동시성제어도 해주어야 하는것이다. 


이진 세마포어도 결국엔 카운팅 세마포어의 일종이다. 하지만 이진 세마포어는 0과1의 값만 가질수 있고 카운팅 세마포어는 0이상의 값을 가질수 있다는점만 다르다. 4개의 공유 자원이 있는 상태에서 생산자 함수에서 도는 쓰레드가 6개 있다고 해보자. 그럼 6개중 맨처음 4개는 카운팅 세마포어에서 슬립 되지 않을것이다. 이 4개중 가장 선두에 있는 쓰레드는 이진 세마포어마저 통과할것이고 크리티컬 섹션에 진입할것이다. 하지만 3개의 쓰레드는 이진 세마포어에서 슬립되어 기다릴것이다. 선두에 있는 스레드가 이진 세마포어에 대해 up 연산을 하게 되면 기다리던 3개의 쓰레드중 하나가 깨어나서 또 다시 크리티컬 섹션에 진입한다. 위의 코드는 이런 구조로 동작한다.



모니터

-> 고수준의(추상화가 많이 된) 동기화 제공

-> 프로시져,변수,데이터구조로 구성 되어있음.

-> 프로세스가 직접적으로 모니터 내부의 값들을 확인할 수 없음. 


모니터는 그 자체로 상호배제와 동기화를 제공한다. 다만 모니터를 사용하려면 프로그래밍 언어가 모니터를 지원해야 한다.

C언어에서는 모니터를 제공하지 않는다.










댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함