Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
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
Archives
Today
Total
관리 메뉴

장미정원

[OS] 동기화을 위한 뮤텍스와 세마포어 본문

CS

[OS] 동기화을 위한 뮤텍스와 세마포어

신희성 2024. 7. 10. 02:01

 

동기화

여러 프로세스나 스레드가 공유자원에 접근하여도 공유자원의 일관성을 유지할 수 있는 것입니다.

 

프로그램에서 여러 쓰레드가 공유자원에 동시에 접근하였을 때 타이밍이나 순서에 따라 결과값이 달라지는 일이 발생할 수 있습니다. 이런 현상을 Race Condition 경쟁상태라고 합니다.

 

이러한 경쟁상태에 의해 프로그램의 의도와 다르게 동작하게 될 위험이 있기 때문에 동기화 작업으로 이러한 공유 데이터의 동시에 접근하는 것을 막기 위해 순서를 제어하여 공유 데이터의 일관성을 유지하여야합니다.

 

공유 데이터의 일관성을 보장하기 위해 한번에 특정 쓰레드나 프로세스만 접근 가능한 영역을 Critical Section 임계영역이라고 하며 이 임계영역에는 특정 프로세스나 쓰레드만 접근을 허용하여 공유 데이터의 일관성을 보장하면서 작업을 진행하는 것을 Mutual Exclusion 상호배제라고 합니다.

 

만약 임계영역에 접근할 수 있는 상태이고 다른 프로세스나 쓰레드가 이 임계영역에 접근하길 원한다면 그 중에 하나는 임계영역에 접근하여 작업이 진행되어야합니다.

어떤 프로세스나 쓰레드가 무한정 임계영역에 접근하지 못하고 대기하는 상태가 일어나지 않게 대기시간은 한정되어있어야 합니다.

 

임계영역의 상호배제를 보장하여 동기화를 실현하려면 을 이용하면 됩니다.

 

스핀락

스핀락은 임계영역에 접근하지 못한다면 계속해서 루프를 돌면서 접근 시도를 하는 것입니다. (busy waiting)

 

위 코드는 스핀락의 동작과정을 간단하게 코드로 구현한 것입니다.

spinLock 메서드를 보면 set 메서드를 실행시킨 후 반환값이 1과 같다면 루프를 돌도록 구현되어 있습니다.

set메서드는 현재 lock값을 받고 lock의 값을 1로 바꾼 후 파라미터로 받은 lock의 값을 반환해줍니다.

 

만약 루프를 통과했다면 임계영역에 진입하여 작업을 수행 후 다시 lock을 0으로 바꾸어줍니다. 이렇게 된다면 루프를 돌고 있던 쓰레드 중 하나가 루프문을 통과하여 임계영역에 진입하게 됩니다.

 

여기서 또 문제가 하나 있습니다. set 메서드에 대한 작업에 대한 상호배제가 이루어지지 않는다면 또 경쟁상태 문제가 발생할 수도 있습니다. 이 부분에 대해서는 운영체제에서 구현된 스핀락은 CPU단에서 해당 연산을 atomic 하게 만들어주고 프로그램에서 스핀락을 구현시 다양한 구현 방법으로 set 연산에 대해 경쟁상태가 일어나지 않게 해줍니다.

 

이러한 스핀락은 임계영역에 접근하기 위해 기다리는 동안 계속해서 lock을 확인하는 루프를 돌아 리소스를 낭비하게 됩니다.

 

뮤텍스

임계영역 접근을 하나의 프로세스나 쓰레드로 제한시키는 장치입니다.

 

대기하는 요청은 큐에 저장 후 락이 해제된다면 큐에서 대기하는 프로세스나 쓰레드를 불러와 임계영역에 접근시킵니다. 즉 Non-Busy-Wait 방식이다. (대기 큐에서 CPU 자원을 내려두고 기다린다.)

 

뮤텍스는 lock을 소유하고 있는 프로세스나 쓰레드가 lock을 해제해야한다. 즉 본인만 lock을 해제할 수 있습니다.

 

 

간단한 뮤텍스의 동작과정입니다. 

defualt value값은 1입니다. 락 획득시 value값이 0이라면 즉 누군가 임계영역에 접근해있다면 해당 쓰레드를 대기 큐에 넣어둡니다. 만약 획득시 0이 아니라면 획득에 성공했기 때문에 value의 값은 0으로 바꾸어두고 임계영역에 접근합니다.

 

임계영역에서의 작업이 끝났다면 락을 해제합니다. 해제시 대기 큐에 대기중인 쓰레드가 있다면 쓰레드 하나를 꺼내 실행시켜 임계영역에 접근하도록 하고 대기 큐에 대기중인 쓰레드가 없다면 value값을 0으로 바꾸고 작업을 종료합니다.

 

세마포어

하나 이상의 프로세스나 쓰레드가 임계영역에 접근 가능하도록 하는 장치입니다.

 

임계영역에 접근 가능한 프로세스나 쓰레드의 수를 정수 값으로 관리하는 장치입니다. 뮤텍스와 동일해보이지만 value값이 1이 아닌 다른 값들이 들어올 수 있습니다. 예를 들어 value가 5라면 최대 5개의 프로세스나 쓰레드가 임계영역에 접근 가능하다. 변기가 5개인 화장실이라고 생각하면 편합니다.

 

value 값을 1을 가지는 세마포어를 이진 세마포어, 1이 아닌 값을 가지는 세마포어는 카운팅 세마포어라고 합니다.

이진 세마포어와 뮤텍스는 비슷해보이지만 분명한 차이점이 있습니다.

 

세마포어로는 순서를 정해줄 때도 사용할 수 있습니다.

 

세마포어는 시그널 매커니즘을 가집니다. 위의 그림을 보았을때 작업 C는 무조건 작업 A가 실행된 이후에 실행됩니다.

프로세스 1과 프로세스 2는 각각 작업 A와 작업 B를 진행합니다. 여기서 둘 중 누가 먼저 작업을 종료하여 SIGNAL이나 WAIT을 호출할 지는 중요하지 않고 작업 A가 끝나야만 작업 C가 진행됩니다.

 

WAIT나 SIGNAL이 서로 다른 프로세스나 쓰레드에서 실행되어도 상관이 없습니다.

 

 

뮤텍스 = 이진 세마포어 ?

 

뮤텍스는 락을 소유하는 프로세스나 쓰레드만이 락을 해제할 수 있지만 세마포어는 그렇지 않습니다.

-> 그렇게 때문에 뮤텍스는 어떤 프로세스나 쓰레드가 락을 해제할지 예상할 수 있습니다.

 

뮤텍스는 priority inheritance 속성이 있지만 세마포어는 그 속성을 가지는것이 불가능합니다.

 

priority inheritance

 

만약 우선순위 스케쥴링으로 컨텍스트 스위칭이 동작하는 상황에서 우선순위가 낮은 P2가 뮤텍스 락을 획득하여 임계영역에 접근하였습니다. 그 후 우선순위가 높은 P1이 뮤텍스 락을 획득하려 했지만 대기 큐에 들어가게 됩니다.

여기서 P2는 상대적으로 우선순위가 낮기 때문에 다른 프로세스에 비해 컨텍스트 스위칭되는 기간이 짧아지고 그에 따라 락 보유 시간이 엄청 길어질 수도 있습니다.

 

 

priority inheritance 속성은 P1이 P2에 의존하고 있는 상황에서는 P2의 우선순위를 P1만큼 높혀서 빨리 임계영역을 빠져나올 수 있게 해줍니다!

 

뮤텍스는 누가 락을 해제할지 예상이 가능하여 priority inheritance가 가능하지만 세마포어는 누가 SIGNAL을 날릴지 예상할 수 없기 때문에 priority inheritance가 불가능합니다.

 

마무리

요즘 관심이 있는 동기화 작업에 대해 여러 구현 방법에 대해 알아보았습니다. 실제로 운영체제에서 어떻게 프로세스와 쓰레드간의 동기화를 처리하는지 알게 되었고 추가로 애플리케이션 개발을 진행 할 때도 뮤텍스와 세마포어의 기술을 사용해서 구현한 모습을 많이 찾아보게 되었습니다.

 

 

참고자료

https://www.youtube.com/watch?v=vp0Gckz3z64&list=LL&index=9

'CS' 카테고리의 다른 글

[CS] sync, async, blocking, non-blocking  (2) 2024.10.15
[OS] 프로세스와 스레드  (5) 2024.08.07