콘텐츠로 건너뛰기
Home » 배리어

배리어

컨디션을 통한 스레드 동기화 예제

동시성을 다룰 때 여러 스레드가 하나의 자원에 순차적으로 접근하게 하거나, 반대로 특정한 시점에 동시에 작동하도록 하는 등의 상황에 제대로 대응할 수 있도록 락이나 이벤트와 같은 동기화 수단을 사용한다. 컨디션은 컨디션 락이라고도 하는데, 간단히 말하자면 이벤트와 락을 적절히 결합한 것이다. 락이나 R락을 사용하는 경우, 락을 획득한 구간의 코드는 항상 하나의 스레드만 진행할 수 있다. 락을 사용하는 중간에 다른 스레드로 사용 권한을 넘기려 한다면 현재 획득한 락을 해제하여 크리티컬 구간을 끝내야 한다. 그런데, 경우에 따라서는 atomic한 자원을 사용하려는 구간에서 해당 자원이 준비되지 않아 구간 내에서 일시적으로 실행을 중단하고 대기해야 하는 상황이 될 수 있다. 이런 경우에 컨디션 락을 사용한다.

컨디션은 락을 획득한 구간내에서 락을 일시적으로 반환하고 기다리는 역할을 가능하게 한다. 컨디션 락을 기다리는 스레드는 락을 해제하면서 블럭된다. 그러면 같은 컨디션락을 획득하려는 다른 스레드에게 제어권이 넘어가는데, 이러한 스레드 중에 해당 자원을 생성하는 역할을 담당하는 스레드가 있다면 이 생산자 스레드는 자원을 생성한 후, 이벤트와 비슷하게 대기 중인 다른 스레드를 깨워주게 된다. 생산자 스레드가 락을 반환하고 나면 중단됐다가 깨어난 스레드는 락을 다시 획득해서 해당 자원을 독점적으로 사용할 수 있게 된다.

중요한 것은 컨디션락은 락의 한 종류이기 때문에 대기중인 상태에서 깨어난 스레드는 그 즉시 실행을 재개하는 것이 아니라, 해당 락을 선점한 다른 스레드가 (이 스레드가 자신을 깨워주었을 것이다.) 락을 반환한 후 다시 그 락 객체를 획득해야 실행을 재개할 수 있게 된다는 것이다.

더 보기 »컨디션을 통한 스레드 동기화 예제

스레드의 시작 시점을 동기화하기

동시성 프로그래밍에서 동기화는 주로 한정된 자원을 두고 여러 스레드가 경쟁하지 않도록 락이나 세마포어를 사용해서 특정한 자원을 액세스하는 시점에서는 여러 스레드가 순차적으로 실행하도록 하는 것에 초점을 맞추고 있다. 하지만 이 외에도 각각의 스레드가 각자가 담당한 작업을 처리하기 위해 준비를 마치고, 다른 스레드의 준비를 기다렸다가 동시에 시작하도록 하는 기법도 필요하다. 이렇게 여러 스레드를 특정한 지점에서 기다리게 한 후 한 번에 깨워서 동시에 시작하게 하는 용도로 사용되는 동기화 프리미티브로는 이벤트와 배리어가 있다.

이런 기법이 가장 흔히 사용되는 경우로는 소켓 서버와 클라이언트를 하나의 스크립트에서 구현해서 스레드로 돌게 할 때이다. 서버의 소켓이 준비되기 전에 클라이언트들이 서버에 connect 될 수 없기 때문이다.

이벤트는 가장 단순한 동기화 프리미티브 중 하나로, 동시에 시작해야 하는 여러 스레드들이 “출발선”에서 이벤트 객체의 .wait() 메소드를 호출하고 대기상태에 들어가도록 한다. 그리고 어느 한 스레드에서 해당 이벤트 객체의 .set() 을 호출하면 해당 이벤트를 대기 중인 모든 스레드에서 wait() 메소드가 리턴되면서 각 스레드가 동시에 시작될 수 있다.

배리어도 비슷하게 여러 스레드를 기다리게하다 한 번에 깨우는 장치인데, 마치 정원이 다 차면 바로 출발하는 버스처럼 작동한다. 즉 이벤트를 기다리는 스레드들은 누군가가 깨워줘야 하는 것에 비해, 배리어 정해진 개수만큼의 스레드가 대기하게 되면 자동으로 해제되면서 동시에 깨어나게 된다.

더 보기 »스레드의 시작 시점을 동기화하기