더북(TheBook)

예를 들어 큐가 있고 큐에서 꺼낸 항목 하나를 저장하는 변수가 있다고 칩시다. 큐는 병렬 자료 구조고 꺼낸 항목은 원자 조작으로만 다룹니다.

ParallelQueue<int> queue;      // 병렬 자료 구조
atomic<int> item;              // 원자 조작 변수
 
void func()
{
  int i = queue.pop();       // 큐에서 꺼낸다.
  item = i;                  // 꺼낸 것을 여기다 넣는다.
}
 
void func2()
{
  int i = item.exchange(0);  // 꺼냈던 항목을 가져와서 사용한다.
  if (i != 0)
  {
      ...;
  }
}

잠금 없는 멋진 코드입니다! 잠금 없이 병렬로 작동하는 프로그램을 만드는 것은 어렵지만, 성능 하락이 없는 이상적인 병렬 처리를 이룩합니다. 실제로 이 예시는 크래시를 일으키지 않습니다. 그러나 문제는 큐와 큐에서 꺼낸 항목의 상태가 항상 일관성을 가진다고 보장할 수 없습니다. 예를 들어 항목이 5개 있는 큐에서 항목을 꺼내 원자 조작 변수에 넣는 과정을 시행하는 아주 짧은 찰나에, ‘큐에서 꺼낸 항목이 아직 원자 조작 변수에 들어가 있지 않음’이라는 상태를 다른 스레드가 만나 버릴 수도 있습니다.

이것을 해결하려면 두 변수가 항상 일관성 있는 상태를 유지해야 합니다. 두 변수를 한꺼번에 보호하는 뮤텍스나 임계 영역을 두고 두 변수를 액세스할 때 그것을 잠그는 것을 예로 들 수 있습니다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.