우리가 흔히 생각하는 동시 의 의미와는 다르게, 동시성 프로그래밍에서의 동시성 은 팔이 8개 달린 사람이 8개의 일을 동시에 처리하는 것이 아니다.
동시성이란 한 사람이 여러 작업을 처리하고 있을 때, 그 작업을 빠르게 바꾸며(context switching) 진행하는 모습이라고 생각하면 된다.
지난 번의 예시처럼, 메일 응대, 프로그래밍, 프로젝트 매니징의 업무를 맡은 한 직원이 있다. 이때 동시성이란, 이 직원이 3개의 업무를 빠르게 바꾸며 진행하는 것이다.
이때 한 직원이 프로세스이고, 직원이 맡은 일 3개는 스레드가 된다. 그러므로 동시성은 thread와 관련되어있다고 생각하면 된다.
이는 보통 I/O bound(입/출력 정보를 처리하는데 많은 시간이 소모되는 장애) 문제에서 해결책으로 제시된다.
여러 작업을 동시에 실행하고 계산한다는 뜻이다. 여기서의 동시 는 우리가 생각하는 '그' 동시 가 맞다.
동시성의 경우, 한 대의 콜라기계에 2개의 대기줄이 서는 느낌이다. 결국 일을 처리할 직원(프로세스)는 하나이고, 대신 2명씩 줄을 서서 달라붙어있으니, 한 사람 -> 그 다음 사람 (context switching) 콜라를 빨리 주는 게 관건이다.
병렬성의 경우, 두 대의 콜라기계에 각각 1개의 대기줄이 서는 느낌이다. 일을 처리할 직원(프로세스)가 2개이고, 한 기계당 줄이 한 줄 밖에 없다. 그러므로, 두 콜라 기계는 말그대로 동시에 콜라를 뽑아줄 수 있게 된다.
작업 스케줄러(task scheduler)는 모든 작업을 매우 정확한 시간과 규칙에 알맞게 지시한다. 모든 작업이 완료될 때까지 실행되어야하는 규칙도 있지만, 언제 어디에서 작업이 실행되는지는 결정하지 않는다.
즉, 첫번째로 실행되는 프로그램이 먼저 끝나지 않을 수도 있다는 말이다. 이러한 비결정적인 형태는 동시성 프로그래밍을 어렵게 하는 원인이다.
두개의 작업이 있다고 하자. (이때의 작업자는 프로세스가 아니라 스레드로 생각하자) 공유된 쓰레기 매립지에 작업자A는 쓰레기를 하나씩 들여놓고, 작업자B는 쓰레기를 하나씩 가져간다. 작업자A는 쓰레기 매립지에 있는 쓰레기가 100개가 될 때까지 반복하고, 작업자B는 쓰레기 매립지에 있는 쓰레기가 -100개가 될 때까지 반복한다. 과연 이 작업이 끝날 수가 있을까?
무도의 의상한 형제들이 생각나는 건 왜일까?
작업 스케줄러가 작업A와 작업B 사이를 계속 반복하면서 영원히 끝내지 않을 수도 있다. 또한 동기화없이 공유자원에 접근하는 멀티스레드 문제도 발생해서 쓰레기 매립지에 몇개의 쓰레기가 남아있을 지 알 수 없는 상황이다.