오늘은 병행 프로세스와 동기화에 대해서 알아보겠습니다.
각 내용에 들어가기 전 병행(Concurrent)의 의미에 대해서 정확히 알고 가야합니다.
병행은 말 그래도 같이 존재하고 있다는 뜻으로 메모리에 다수의 프로세스가 같이 존재한다는 것과 같습니다.
✅ 프로세스 여러 개가 동시에 실행되는 것을 의미합니다.
프로세스들이 공유 데이터에 대해 서로 접근을 시도하는 상황을 경쟁 상태(Race Codition)라고 합니다.
이런 경쟁 상태 속에서 상호배제, 교착상태(Deadlock), 기아(Starvation)와 같은 문제들이 발생합니다.
<출처: http://sqlmvp.tistory.com/176>
➡️ 두 개 이상의 프로세스가 동시에 사용할 수 없는 자원을 임계자원(Critical Resource)라고 합니다. 그리고 이에 대해 접근하고 실행하는 프로그램 내의 코드 부분을 임계영역(Critical Section)이라고 합니다.
임계영역의 성공적인 실행을 위해서는 우선적으로 상호배제가 지켜져야 합니다.
✅ 우선 parbegin/parend 구조부터 살펴보겠습니다.
1: parbegin
2: statement_1
3: statement_2
4: ...
5: statement_n
6: parend
➡️ parbegin 과 parend 사이에 존재하는 n 개의 문장들이 동시에 수행될 수 있다는 것을 뜻합니다.
단일 처리기 시스템의 경우면 각 문장의 수행 순서를 임의로 해도 되고 다중 처리기의 경우에는 각 문장을 병렬적으로 실행하겠다는 뜻이 됩니다.
✅ 두 프로세스 간의 상호배제를 해결한 알고리즘입니다.
✅ n개의 프로세스들을 대상으로 하는 상호배제 알고리즘입니다.
임계영역의 진입을 막기 위해서 while문을 계속해서 돌리는 것을 확인할 수 있습니다. 이는 CPU가 가동 중이지만 유용한 곳에 사용되지 못하는 것입니다.
이런 현상을 바쁜 대기(Busy Wait) 또는 스핀락(Spinlock)이라고 합니다.
while(true) do
.
.
Interrupt Disable;
<critical section>
Interrupt Enable;
.
.
endwhile;
기계명령어인 testandset과 exchange 명령어에 대해서 먼저 살펴봅니다.
[testandset]
[exchange]
➡️ 기계명령어로서 원자적으로 실행 도중 끊김 없이 완료되는 연산입니다.(Indivisable)
<testandset과 exchange를 사용한 상호배제>
✅ 세마포어는 세 개의 특수한 명령들만 접근할 수 있게 허용되는 보호된 변수입니다.
[Block and wakeup 방식]
P(S): if (S>0) then S = S-1;
else S > 0 조건이 만족될 때까지 큐에서 대기;
V(S): if(큐에서 대기 중인 프로세스들이 존재)
then 그 중의 한 프로세스를 준비 또는 실행 상태로 만듦;
else S=S+1;
[Busy-Wait 방식]
P(S){
while(S<=0); // Busy-wait //
S--;
}
V(S){
S++;
}
const int n = /* 프로세스 개수 */;
semaphore s = 1; // 이진 세마포어
void process(int i) {
while (true) {
P(s);
/* 임계 영역(Critical Section)*/
V(s);
/* 임계 영역 이후 코드 */
}
}
void main() {
parbegin (P(1), P(2), ..., P(n));
}
✅ 모니터란 공유 데이터들과 이 들에 대한 임계영역들을 관리하는 소프트웨어 구성체입니다.
👍 여기서 중요한 점은 언제나 모니터의 진입을 한 프로세스로 제한함으로써, 상호배제를 자연스럽게 실현하게 됩니다.
cwait(c)는 이 연산을 호출한 프로세스를 조건 c의 큐에 대기시키고 다른 프로세스의 모니터 진입을 가능하게 합니다.
csignal(c)는 cwait(c)에 의해 대기되었던 프로세스를 재개시키고 자신은 신호자 대기 큐로 비켜줍니다.
오늘은 상호배제 기법, 세마포어, 모니터에 대해서 알아보았습니다.
다음 시간에는 교착 상태(Deadlock)에 대해서 공부해보겠습니다. 😃
잘 읽었습니다 고생 많으셨어요👏🏻