제임스딘딘의
Tech & Life

개발자의 기록 노트/Linux

리눅스에서의 세마포어 (Semaphores in Linux)

제임스-딘딘 2012. 10. 7. 15:25

리눅스에서의 세마포어 (Semaphores in Linux)



 일반적으로 상용 어플리케이션은 멀티스레드 어플리케이션이다.

 상용 어플리케이션중 멀티스레드가 아닌 어플리케이션은 상상하기 힘들다.

어플리케이션과 시스템의 성능(응답성)을 높이기 위해서 어플리케이션은 반드시 멀티스레드를 이용한 접근을 해야만 한다. 그러나, 인생의 대부분은 대가없이 얻어지는 것은 없듯이, 어플리케이션에서 멀티스레드의 특성을 활용해야 할 필요가 있다면, 다음과 같은 몇가지 이슈와 부딪히게 된다. 


바로 교착상태(dead lock), 경쟁상태(race condition), 스레드의 잘못된 동작 등이다.

 이러한 이슈들을 극복하기위해, 운영체제는 뮤텍스, 세마포어, 시그널, 배리어와 같은 도구모음을 제공하여, 멀티프로세스와 멀티스레드 환경에서의 문제를 해결한다.

 이 포스팅은 이러한 도구중 하나인 세마포어에 대해 논의하고, 그것들에 대한 몇가지 심화적인 내용을 제공한다.



세마포어 개요

 세마포어는 사실 간단하다. 세마포어는 자원의 상태를 나타내는 간단한 카운터로 생각할 수 있다. 

그런데, 이 카운터는 사용자가 임의대로 접근 할 수는 없는 보호받는 변수라고 가정해보자.

그리고 리눅스에서 이러한 변수의 보호장치는 바로 '커널'이다.


이 세마포어 변수의 사용법은 간단하다. 만약 카운터가 0보다 크다면, 자원은 사용가능한 것이고, 카운터가 0이거나 0보다 작다면 자원은 busy 상태이거나 다른 누군가에 의해 사용되고 있는 것이다. 이 간단한 메커니즘이 멀티스레드나 멀티프로세스 기반의 어플리케이션의 동기화를 돕는다.

 

세마포어는 Edsger Dijkstra(에드거 다익스트라)에 의해 개발 및 제안되었고, 리눅스를 비롯한 오늘날의 여러 운영체제들에서 동기화(Synchronization)의 목적으로 사용되곤 한다. 같은 메커니즘은 이제 어플리케이션 개발자 역시 사용할 수 있다. 동기화 메커니즘은 또한 프로세스간 통신(IPC)에서도 가장 중요한 요소 중 하나이다.


세마포어는 공유되는 자원의 개수에 따라 2진(Binary, 바이너리) 세마포어가 될 수도 있고 계수(Counting, 카운팅) 세마포어가 될 수도 있다. 만약 단일 자원이 사용된다면, 단지 하나의 세마포어만을 동기화목적으로 사용 할 수 있다. 이런 경우에 세마포어는 2진(바이너리) 세마포어이다. 사용자간 공유되는 자원의 수가 하나보다 큰 이외의 모든 경우에는 카운팅 세마포어로서, 2개 이상의 세마포어를 사용할 수 있다.


세마포어는 기본적으로 2개의 동작(Operation)으로 구현한다. 


하나는 세마포어 변수를 기다리는 것이고, 다른 하나는 세마포어 변수에 시그널을 보내는 것이다. 세마포어는 카운터만은 아니기 때문에 다음의 알고리즘이 두개의 세마포어 오퍼레이션을 표현한다.




가정:

s는 세마포어 변수이다.

W(s)  는 세마포어를 대기하는 것을 나타낸다.

P(s) 는 세마포어에 시그널을 보낼수 있음을 의미한다.


알고리즘:


W(s)

while (s <= 0) {
	//do nothing
}
s=s-1;


P(s)

s=s+1;


위의 알고리즘으로 부터 세마포어의 대기연산은 세마포어 카운터에서 1을 감소하는 것 외에는 아무것도 하지 않음을 쉽게 이해 할 수 있다. 시그널을 보내는 연산은 정확히 반대로, 세마포어 카운터를 1 증가한다.




Difference Between Semaphores and Mutex

 여기까지 읽었다면 몇가지 명확한 차이가 드러난다. 그러나 뮤텍스와 세마포어의 두드러진 차이점을 다시한번 여기서 짚고 넘어가보자.


1. 세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다. 

이것은 간단히 말해서 binary 세마포어는 뮤텍스로써 사용가능하지만, 뮤텍스는 결코 세마포어로써의 기능을 보여 줄 수 없다.(counting 세마포어로써의 기능을 말함)


2. 세마포어와 뮤텍스 둘 다 (적어도 최신 커널에서는, 2007년 기준) 자연스럽게 비 재귀적이다.


3. 세마포어는 무엇에도 소유되지 않는다. 반면에 뮤텍스는 소유되며, 뮤텍스 소유자는 그것들에 대해 책임이 있다. 이것은 디버깅 측면에서 중요한 차이점이다.


4. 뮤텍스의 경우, 뮤텍스를 소유한 스레드가 뮤텍스를 해제해야할 책임이 있다. 그러나 세마포어의 경우에는, 이런 상태가 필요없다. 다른 어떤 스레드들도 세마포어를 해제하기 위해 sem_post( ) 함수를 사용해서  신호를 보낼 수 있다.


5. 결정적으로 뮤텍스는 재진입 코드의 영역(크리티컬 섹션)으로의 연결을 직렬화 하는데 사용되고, 하나보다 많은 (2개 이상의 ) 스레드가 병행적으로 (concurrently) 실행할 수 없다. 정의에 의하면 세마포어는 최대 숫자까지 공유자원에 대한 사용자의 동시 사용을 제한한다.