락(lock)이란?
- 공유 자원을 하나의 쓰레드가 사용하고 있을 때 다른 쓰레드가 공유 자원을 사용하지 못 하도록 제한을 거는 것이다.
공유 자원 이란?
- 전역 변수
- DB
- 동적 객체
- 메모리
등의 여러 쓰레드가 접근하여 사용하는 공동의 자원이다. 지역 변수는 단일 쓰레드 안에서 사용되는 자원으로 공유 자원이라고 할 수 없다.
Lock의 필요 이유
위의 상황 처럼 쓰레드1과 쓰레드2가 동시에 같은 전역 변수에 접근한다고 가정한다면 두 개의 쓰레드가 완료된 후에는 값이 2가 되어야 하는지 1이 되어야 하는지 알 수 없을 것이며 매번 값이 변경될 가능성도 있을 것이다. 이처럼 알 수 없는 비정형적인 결과를 발생 시킬 수 있으며 동시에 접근 쓰레드들은 공유 자원을 사용하기 위한 race condition 상태가 되게 된다.
이를 해결하기 위한 방법은 쓰레드를 순차적으로 실행하여 동기화를 진행하는 것이고 이를 위해서는 Lock을 사용하여야한다.
Lock의 종류
임계 구역(Critical Section)
- 프로세스 간의 공유 자원의 접근의 문제를 막기 위해서 한 번에 하나의 프로세스만 이용하여서 접근을 제한 하는 방식으로 같은 프로세스안의 쓰레드끼리는 동기화를 진행하여서 프로세스를 진행한다. 따라서 프로세스 안에서도 같은 자원에 대해서는 순차적으로 쓰레드가 실행된다.
- 대기하고 있는 쓰레드는 CPU를 점유하지 않고 동작이 필요한 쓰레드에게 CPU를 넘기는 동작인 컨텍스트 스위칭이 발생한다.
스핀락(Spinlock)
- Lock과 Unlock을 사용하여서 공유 자원에 대한 접근을 관리하는 방식이다. 대기 중인 쓰레드는 CPU를 점유한 상태로 공유 자원의 락이 해제되었는지 지속적으로 확인하는 Busy Waiting 상태가 되게 되어 단일 CPU 경우에는 무한 루프에 빠지게 된다.
- CPU를 점유한 상태로 공유 자원의 상태를 지속적으로 확인하기 때문에 빠르게 작업을 수행 할 수 있다. CPU 점유가 다른 프로세스의 작업에 지연을 줄 수 있어 짧게 수행하는 작업에서 사용한다.
뮤텍스(Mutex)
- 스핀락과 동일하게 Lock과 Unlock의 상태로 권한을 획득하지만 Busy Waiting 상태로 기다리지 않고 Sleep 상태로 대기하다 Wakeup 상태가 되면 권한 획득을 시도한다.
- 공유 자원을 선점한 쓰레드가 작업 시작전 acquire()로 자원에 접근하려는 다른 쓰레드를 sleep 상태로 만든다. 작업이 완료 되면 release()로 sleep중인 쓰레드에게 알려 wake up 상태로 만들어 자원 권한 획득을 시도하도록한다.
- 쓰레드가 작업을 하기전 lock의 권한을 가지고 작업 후 lock 권한을 반환하는 방식이다.
- sleep 상태로 CPU를 점유하지 않기 때문에 길게 처리하는 작업에서 주로 사용 한다.
세마포어(Semaphore)
- 하나 이상의 쓰레드가 공유 자원에 접근을 허용하는 방식이다.
- lock, unlock과 같이 권한을 획득, 해제 방식이 아닌 값을 올리고 내리는 방식으로 사용한다.
- 공유 자원에 접근 시 semWait를 호출하여 접근 가능 여부를 확인하여 semWait를 빠져나오고 임계 구역에 들어간다. 작업을 완료 후 semSignal을 호출하여 임계 구역을 빠져나온다.
- semWait : 세마포어의 값을 감소 시킨다. 세마포어가 음수가 되면 쓰레드는 임계 구역에 들어가지 못하고 블락된다.
- semSignal : 세마포어의 값을 증가 시킨다. 세마포어의 값이 양수가 아니면 블락된 쓰레드를 활성화 시켜준다.
- 두개의 쓰레드가 동식에 시작되면 양쪽 다 signal을 받기 전까지 wait 상태를 유지하는 데드락(Dead lock)이 발생할 수 있다.
참고 자료
728x90
'주제 정리' 카테고리의 다른 글
[운영체제] 블로킹 vs 논블로킹, 동기 비동기 (0) | 2021.09.16 |
---|---|
[아키텍처]마이크로 서비스 (0) | 2021.08.19 |
[JAVA] HashSet (0) | 2021.08.13 |
[JAVA] HashTable, HashMap (0) | 2021.08.12 |
Object 객체 탐구 (0) | 2021.08.07 |