DeadLock이란 2개 이상의 작업이 서로의 종료를 기다리며 아무것도 완료하지 못하는 상태를 의미한다. DeadLock의 조건에는 4가지가 존재한다.
작업이 필요로 하는 자원에 대해 배타적인 통제권을 가지는 것을 의미한다.
각 작업들이 자원을 점유한 상태로 다른 작업의 종료를 기다리는 것을 의미한다.
하나의 작업이 자원을 점유하고 있을 때 다른 작업이 그 자원을 빼앗을 수 없는 것을 의미한다.
각 작업이 다음 작업이 필요한 자원을 가지고 있는 것을 의미한다.
임계 영역이란 공유된 자원을 수정하는 코드 부분을 의미한다. OS는 임계 영역에 여러 개의 작업이 들어갈 수 없도록 관리해주어야 한다.
상호 배제를 뜻하는 말로, 임계 영역을 가지는 쓰레드들의 Running time을 겹치지 않도록 해주는 기법이다. 임계 영역에 단 하나의 쓰레드만 접근할 수 있도록 Lock, Unlock을 통해 관리하게 된다. 임계 영역에 들어온 쓰레드는 Lock에 대한 권한을 가지게 되고, 다른 쓰레드들은 Unlock이 될 때까지 기다렸다가 나중에 공유 자원에 접근하게 된다. 이진 세마포어와 같은 개념이다.
세마포어는 임계 영역에 여러 프로세스가 접근하지 못하도록 하는 기법이다. 세마포어는 이를 위해 현재 공유 자원의 상태를 나타내는 변수를 카운터 변수를 사용하는데, 이 변수는 OS나 커널 값으로 저장되고, 프로세스가 들어갈 때마다 1씩 감소하게 된다. 반대로 프로세스가 수행을 끝내고 나오면 1이 증가한다. 뮤텍스와 다르게 2 이상의 수로도 카운터 변수를 선언할 수 있다. 이를 통해 임계 영역에 들어갈 프로세스의 갯수를 통제할 수 있다. 만약 임계 영역에 다른 프로세스가 존재할 경우, 일정한 시간동안 대기한 후에 임계 영역에 접근한다.
하나의 프로세스 내의 다른 쓰레드 간의 동기화에 사용된다. 모니터는 프레임워크나 라이브러리에서 제공되고, 일련의 동기화 작업들이 캡슐화되어 있어 synchronized, wait(), notify()를 통해 편하게 동기화 할 수 있다.
스핀 락은 임계 영역에 접근하지 못할 경우에 접근이 가능할 때까지 루프를 돌며 재시도 하는 방식으로 구현된 락으로 busy waiting과 같은 방식이다. 루프를 돌기 때문에 기다리는 동안에도 CPU를 사용한다.
스핀 락은 OS의 스케줄링 지원을 받지 않기 때문에 Context switch를 하지 않는다. 짧은 시간 안에 임계 영역에 들어갈 수 있다면 Context switch가 없으므로 효율이 좋지만, 오랜 시간 기다린다면 CPU를 다른 쓰레드에게 양보하지 않아 CPU 효율을 떨어트린다.
Context switch가 일어나지 않기 때문에 멀티 프로세서 시스템에서만 사용이 가능하다.
위의 동기화 기술들은 임계 영역을 Lock한 후 작업을 수행한다. 이렇게 되면 한 개의 쓰레드가 해당 임계 영역 전체를 점유하기 때문에 다른 쓰레드들은 이를 기다려야 하고, 성능 상의 낭비가 발생한다.
Atomic 연산은 Non-blocking, Lock-Free한 방식으로 동기화 문제를 해결한다.
멀티 쓰레드, 멀티 프로세스 환경에서 각 CPU는 메인 메모리에서 변수 값을 참조하지 않고, 각 CPU의 캐시 영역에서 메모리 값을 참조한다. 이때 메인 메모리의 값과 캐시 상의 값이 다른 경우가 있는데, 이를 가시성 문제라고 한다.
이때 CAS(Compare And Swap) 알고리즘을 통해 현재 쓰레드에 저장된 값과 메인 메모리에 저장된 값을 비교하고, 일치할 경우 새로운 값으로 교체하고, 일치하지 않을 경우, 실패하고 재시도한다. 이러한 방식은 CPU캐시에서 잘못된 값을 참조하는 가시성 문제를 해결한다. 연산의 결과는 쓰기가 제대로 이뤄졌는지 나타나고, 이 연산은 Atomic하기 때문에 새로운 값이 최신의 정보임을 보장한다.