1. 개요
수년 동안 병행성 관련 오류(버그) 해결을 위해 연구자들이 엄청난 시간과 노력을 들였다.
대부분의 초기 연구는 교착 상태(deadlock)
에 초점이 맞추어져 있었다.
2. 오류의 종류
복잡한 병행 프로그램에서는 어떤 종류의 문제점들이 발생할까?
대부분의 오류는 교착 상태와 무관한
오류이며 나머지 오류들이 교착 상태 관련 오류이다.
3. 비 교착 상태 오류
Lu
의 연구 결과를 따르면 절반 이상의 버그는 교착 상태와 무관하다.
대표적인 오류는 원자성 위반(atomicity violation)
오류와 순서 위반(order violation)
이다.
원자성 위반에 대한 정의는 이렇다.
다수의 메모리 참조 연산
들 간에 있어 예상했던 직렬성(serializability)
이 보장되지 않았다.
즉, 코드의 일부에 원자성
이 요구되었으나, 실행
시에 그 원자성이 위반되었다.
이러한 문제는 공유 변수 참조
앞뒤에 락
을 추가하여 어느 스레드든 proc_info 필드 접근 시, proc_info_lock 이라는 락 변수를 획득토록 한다.
순서 위반에 대한 정의는 다음과 같다.
두 개의 메모리 참조
간의 순서
가 바뀌었다.
즉, A가 항상 B보다 먼저 실행되어야 하지만 실행 중에 그 순서가 지켜지지 않았다.
이러한 오류를 수정하는 방법은 순서를 강제
하는 것이다.
앞에서 논의했던 것처럼 이러한 종류의 동기화에는 컨디션 변수
가 잘 맞는다.
4. 교착 상태 오류
앞서 다룬 병행성 관련 오류 외에 복잡한 락 프로토콜을 사용하는 다수의 병행 시스템에서 교착 상태(deadlock)
라는 고전적 문제가 발생한다.
예를 들어 락 L1을 갖고 있는 스레드 1이 또 다른 락 L2를 기다리는 상황에서 불행하게도 락 L2를 갖고 있는 스레드 2가 락 L1이 해제되기를 기다리고 있을 때 교착 상태가 발생한다.
그렇다면 교착 상태는 왜 발생하는가?
한 가지 이유는 코드가 많아지면서 구성 요소 간에 복잡한 의존성
이 발생하기 때문이다.
또 다른 이유는 캡슐화(encapsulation)
의 성질 때문이다.
교착 상태가 발생하기 위해서는 네 가지 조건
이 충족 되어야 한다.
상호 배제(Mutual Exclusion): 스레드가 자신이 필요로 하는 자원에 대한 독자적인 제어권
을 주장한다
점유 및 대기(Hold-and-wait): 스레드가 자신에게 할당된 자원
을 점유한 채로 다른 자원을 대기한다
비 선점(No preemption): 자원(락)을 점유하고 있는 스레드로부터 자원을 강제적
으로 빼앗을 수 없다
환형 대기(Circular wait): 각 스레드는 다음 스레드가 요청한 하나 또는 그 이상의 자원(락)을 갖고 있는 스레드들의 순환 고리
가 있다
5. 회피
어떤 시나리오에서는 교착 상태를 예방하는 대신 회피
하는 것이 더 유용할 때가 있다.
회피하기 위해서는 실행 중인 여러 스레드가 어떤 락을 획득하게 될 것인지에 대해 전반적으로 파악하고 있어야 하며 그것을 바탕으로 스레드들을 스케줄링 하여 교착 상태가 발생하지 않도록 그때그때 보장한다.
6. 발견 및 복구
마지막 전략은 교착 상태 발생을 허용
하고, 교착 상태를 발견하면 복구
토록 하는 방법이다.