요즘엔 “7가지 동시성 모델” 이라는 책을 읽고 있습니다. 쓰레드와 잠금장치, 함수형 프로그래밍(내가 가장 관심있는), 람다 아키텍쳐 등과 같은 부분을 심도있게 다루는 것 같아보여 출퇴근시간에 가볍게 볼까라는 생각으로 책을 구매했지만 만만치 않아보입니다. 어찌어찌 읽는다 한들 그냥 가볍게 이 책을 읽고 지나치기엔 저의 한없이 인간적인 기억력 덕분에 의미없이 지나갈 것 같아 조금 걱정입니다. 그래서 개념정리를 위한 포스팅을 하는것이 좋을것 같아 이렇게 키보드를 두드립니다. 이제 싱글코어에서 멀티코어로의 변화에 있어 동시성을 위한 코드는 어떻게 같이 맞추어 변화할수 있을지에 대해 생각해보고 그에 대한 정리를 포스팅하겠습니다. 기존 포스팅과는 달리 여러편으로 나누어서 해보도록 하겠습니다.
동시성과 병렬성
동시성과 병렬성은 다른 의미입니다. 동시성은 여러 일을 한꺼번에 다루는데 관한 것이고, 병렬성은 여러 일을 한꺼번에 실행하는데 관한 것입니다. 내가 컴퓨터를 하고 커피를 마시며 대화를 하는 것은 동시성입니다. 청첩장을 100장 만들어야 하는데 다섯명이서 똑같은 카드를 20장씩 만드는 것은 병렬성입니다. 병렬성과 동시성이 공유하는 속성은 작업이 한번에 하나씩 순서대로 이루어지는 전통적인 순차적 프로그래밍을 넘어서는데에 있습니다.
동시성의 특징
실 세계는 동시적입니다. 그렇기 때문에 소프트웨어가 세상과 상호작용하기 위해서는 소프트웨어도 동시적이어야 합니다. 분산 소프트웨어는 장애에 강합니다. 시스템의 일부는 유럽에 두고 나머지는 미국에 두는 식의 분산은 탄력성을 갖게 합니다. 동시성은 독립성을 가질 수 있습니다. 소프트웨어의 버그가 발생한다면 하나의 작업이 다른 수많은 작업들에 대해 영향을 주지 않아야 합니다. 순차적으로 동작하는 소프트웨어는 동시적 소프트웨어의 탄력성과 독립성을 따라가지 못합니다. 동시성은 복잡한 세계에 대응할 수 있는 방법입니다. 본래 현실의 동시적인 속성을 순차적으로 구현하다보면 예상할수 없는 문제에 직면할 수 있습니다. 현실세게의 동시성은 동시적인 소프트웨어로 동일한 구조를 가지게 하는것이 더욱 수월할 수 있습니다.
스레드와 잠금장치
스레드와 잠금장치를 이용하는 프로그래밍은 원시적이지만 향후 동시성의 다른 모델의 근간이 되기도 합니다. 그렇기 때문에 정리하고 넘어가 보도록 하겠습니다. 우선, 스레드와 잠금장치는 실제 하드웨어가 동작하는 방식을 그대로 옮긴것과 다르지 않습니다. 이는 장점이 될수도 단점이 될수도 있습니다. 이들은 너무 단순해서 대부분의 언어가 이런 기능을 제공합니다. 하지만 단순하고 제약이 없는 만큼 정확히 이해하지 못하고 코드를 작성하는 프로그래머의 실수로부터 보호해줄수 있는 기능도 존재하지 않습니다. 유지보수 측면에서도 어려워 지는것은 당연한 결과일 것입니다.
상호배제와 메모리모델
상호배제란 잠금장치를 사용하는 것은 특정 데이터에 접근하는 스레드가 한번에 하나만 존재하도록 강제하는 것입니다. 여러개의 스레드가 공유된 메모리에 접근할 때에는 서로가 서로의 동작에 영향을 줄 수 있습니다. 이는 매 번 결과를 보장해줄수 없다는 뜻입니다. 이러한 상황에 대한 해법은 메모리 내 데이터에 대한 접근을 동기화 하는것입니다. 그렇게 하기 위해서는 잠금장치를 이용해야 합니다. (Java의 synchronized) 와 같은 잠금장치를 통해 공유된 데이터에 대한 접근을 한번에 한 스레드만 할 수 있도록 하면 잠금장치를 걸어놓은 상태에서는 타 스레드가 접근하지 않고 대기하게 됩니다. 이런식으로 잠금장치를 활용하게 되면 매번 같은 결과를 보장받을 수 있을 것입니다.