잠금 세분성

멀티프로세서 환경에서 작업하는 프로그래머는 공유 데이터에 사용하도록 작성해야 하는 개별 잠금의 개수를 결정해야 합니다. 전체 공유 데이터 항목 세트를 직렬화하는 하나의 잠금이 있는 경우에는 잠금 경합이 발생할 가능성이 놓습니다. 광범위하게 사용되는 잠금이 있으면 시스템 처리량에 상한이 설정됩니다.

서로 다른 데이터 항목에 고유 잠금이 있으면 두 개의 스레드에서 해당 잠금을 사용하기 위해 경합할 가능성이 낮습니다. 그러나 각 추가 잠금 호출과 잠금 해제 호출에서 프로세서 시간을 사용하므로 여러 잠금이 있으면 교착 상태가 발생할 가능성이 있습니다. 간단히 말해 교착 상태는 다음 그림에 표시된 상황입니다. 여기서 스레드 1은 잠금 A를 소유하고 잠금 B를 대기 중입니다. 한편 스레드 2는 잠금 B를 소유하고 자금 A를 대기 중입니다. 두 프로그램 모두 교착 상태를 해제하는 unlock() 호출에 도달할 수 없습니다. 일반적인 교착 상태 예방법은 주어진 잠금 세트를 사용하는 모든 프로그램이 항상 정확히 같은 순서로 잠금을 확보해야 하는 프로토콜을 설정하는 것입니다.

그림 1. 데드락. 다음 그림에 표시된 교착 상태에서는 스레드 1 열이 잠금 A를 소유하고 잠금 B를 대기 중입니다. 한편 스레드 2 열은 잠금 B를 소유하고 잠금 A를 대기 중입니다. 두 프로그램 모두 교착 상태를 해제하는 잠금 해제 호출에 도달할 수 없습니다.
교착 상태

큐잉 이론에 따르면 자원의 유휴 시간이 짧을수록 자원을 얻기 위해 대기하는 평균 대기 시간이 길어집니다. 관계는 선형적이지 않습니다. 잠금이 두 배가 되는 경우 해당 잠금을 기다리는 평균 대기 시간은 두 배를 넘습니다.

잠금 대기 시간을 줄이는 가장 효율적인 방법은 잠금으로 보호되는 내용의 크기를 줄이는 것입니다. 이에 대한 몇 가지 지침은 다음과 같습니다.

  • 잠금 요청 빈도를 줄이십시오.
  • 구성요소의 모든 코드가 아니라 공유 데이터에 액세스하는 코드만 잠그십시오(그러면 잠금 보유 시간이 줄어듭니다).
  • 전체 루틴이 아니라 특정 데이터 항목 또는 구조만 잠그십시오.
  • 잠금을 루틴이 아니라 특정 데이터 항목 또는 구조와 항상 연관시키십시오.
  • 대형 데이터 구조의 경우 전체 구조에 대한 하나의 잠금을 선택하지 말고 구조의 요소마다 하나씩 잠금을 선택하십시오.
  • 잠금을 보유 중인 동안에는 동기 입출력 또는 기타 블로킹 활동을 수행하지 마십시오.
  • 구성요소의 동일한 데이터에 대해 둘 이상의 액세스 권한이 있는 경우 해당 액세스 권한을 한 번의 잠금/잠금 해제 조치로 처리할 수 있도록 함께 이동하십시오.
  • 이중 웨이크업이 발생하지 않게 하십시오. 잠금 상태에서 일부 데이터를 수정하고 이를 다른 사람에게 알려야 하는 경우 웨이크업을 통지 전달하기 전에 잠금을 해제하십시오.
  • 두 개의 잠금을 동시에 보유해야 하는 경우에는 가장 많이 사용되는 잠금을 마지막에 요청하십시오.

한편 세분성이 지나치게 세밀하면 잠금 요청과 잠금 해제의 빈도가 늘어나 추가 명령어가 추가됩니다. 지나치게 세밀한 세분성과 너무 거친 세분성 사이에서 균형을 찾아야 합니다. 최적의 세분성은 시행 착오를 통해 발견되며 MP 시스템에서 가장 어려운 과제 중 하나입니다. 다음 그래프는 잠금의 처리량과 세분성 사이의 관계를 표시합니다.

그림 2. 처리량과 세분성 간의 관계. 이 그림은 간단한 두 개의 축으로 이루어진 차트입니다. 세로 축 또는 y 축은 처리량을 나타냅니다. 가로 축 또는 x 축은 척도가 커질수록 세밀한 상태에서 거친 상태가 되는 세분성을 나타냅니다. 늘어난 종형 곡선은 처리량에 대한 세분성의 관계를 표시합니다. 세분성이 세밀한 상태에서 거친 상태가 될수록 처리량이 점점 늘어나 최대 레벨이 된 후 천천히 줄어들기 시작합니다. 이는 최대 처리량에 도달하려면 세분성의 절충이 필요함을 나타냅니다.
처리량과 세분성 사이의 관계