Stay Hungry Stay Foolish

운영체제

[OS] 07. 프로세스 간 동기화 및 통신

dev스카이 2023. 10. 16. 11:03

(1) 개요

Concurrent Processes (병행 프로세스)

  • 두 개 이상의 프로세스들이 동시에 수행됨을 의미한다.
    • 독립적으로 작업이 수행되며, 다른 프로세스와 협력하여 기능 수행도 가능하다.
    • 협력 수행 시에 프로세스 간의 *동기화 또는 통신이 필요하다.
    • 공유 자원을 가지고 수행한다.
  • 병행 프로세스 처리는 제한된 자원을 공유하기 위해 *상호작용이 필요하다.
  • 상호 작용하는 프로세스들을 동기화하지 않으면 문제가 발생할 수 있다.
    • Deadlock 문제, Critical Section 문제, 결과를 예측할 수 없는 상황 등이 발생할 수 있다.

*동기화 : 협력하는 프로세스 간에 실행 순서가 필요하다. ex)입금이 끝나야 출금이 수행되어야 한다.
*상호작용 : 제한된 자원을 공유하기 위함이며, 상호작용하는 프로세스는 순서에 맞게 실행되도록 동기화가 되어야 한다.

 

(2) Concurrent Processes Promblem

✔  병행 프로세스 처리 과정에서 OS가 반드시 해결해야 할 것

  • 다른 Process가 관여하지 못하도록 공유 자원의 상호 배타적인 사용(Mutual exclusion)을 보장해야 한다.
  • 하나의 기능을 공동으로 사용하여 수행하는 두 프로세스 간의 동기화(Synchronization)문제를 해결해야 한다. -> 프로세스 간에 순서를 정해서 한 프로세스만 처리한다.
  • 두 개 이상의 프로세스의 실행 순서와 무관하게 항상 같은 결과를 얻을 수 있어야 한다.(일관성)
  • Deadlock 문제를 해결할 수 있어야 한다.
  • 프로세스 간에 자료 교환을 위한 메시지 전달 방식과 같은 통신 문제(Communication)의 해결이 필요하다.

 

➤  Critical Section (임계 구역)

  • 어떤 프로세스가 공유 자원을 접근하면, 그 프로세스는 임계구역에 있다고 한다.
  • 임계구역에 접근한 프로세스는 *상호 배제를 보장받아야 한다.
  • 임계구역은 가능한 한 빨리 수행되어야만 하며, 프로세스가 임계구역에 들어간 후 블록 상태가 되어서는 안 된다.

*상호배제(Mutual Exclusion) : 하나의 프로세스만 공유 자원에 대해 배타적으로 접근하고 나머지 프로세스들은 공유 데이터의 접근할 필요가 있더라도 기다려야 한다.

 

 

➤  Mutual Exclusion (상호 배제)

  • 다수의 프로세스들이 하나의 공유 자원(임계 구역)을 상호 배타적으로 사용한다.(동시 사용 불가)
  • 공유 변수에 접근 중인 하나의 프로세스를 제외한 다른 프로세스들이 공유 변수를 접근하지 못하게 제어하는 기법이다.

수행중인 프로세스에서 save가 되기 전에 다른 프로세스가 수행되면 옳은 답이 나오지 않는다.

 

✔  Mutual Exclusion Algorithm 요구 조건

  • 공유자원에 대해서는 어느 한 순간에 반드시 하나의 프로세스만이 임계구역에 진입해야 한다.
  • 임계구역에 접근하고자 하는 프로세스의 수행이 무한 대기하지 않아야 한다.
  • Starvation이 발생하지 않도록 해야 한다.
  • Deadlock이 발생하지 않도록 해야 한다.
  • 임계구역이 사용 중이 아니면 임계구역에 진입하기를 원하는 프로세스에게 즉시 진입하도록 허용해야 한다.
  • 임계구역에 진입한 프로세스는 일정한 시간 내에 임계구역을 빠져 나와야 한다.

 

(3) Mutual Exclusion Algorithm (상호 배제 알고리즘)

➤  1단계 Mutual Exclusion Primitive(1단계 알고리즘)

  • 한 순간에 단지 하나의 프로세스만이 임계 구역에 진입하도록 보장해야 한다.(상호배제 보장)
  • 한 개의 공유 변수를 이용한다.(processnumber) -> 동기화를 위해 사용하는 공유 변수다.

Pseduo Code

program mutex1;
var processnumber;

p0(){ //프로세스 p0의 임계구역 procedure
    while(true){
        while(processnumber != 0) //p1의 진입여부 확인
        ;
        critical_section
        processnumber = 1; //p1에게 임계구역 진입순서 양보
    }
}
p1(){ //프로세스 p1의 임계구역 procedure
    while(true){
        while(processnumber != 1) //p0의 진입여부 확인
        ;
        critical_section
        processnumber = 1; //p0에게 임계구역 진입순서 양보
    }
}
//main
    processnumber = 1; //공유변수를 p1 진입 순서로 초기화
    parbegin
     p0(); //p0과 p1의 동시 수행 -> 어떤 것이 먼저 수행될지는 상황에 따라 변경
     p1();
    Parend

1단계 알고리즘은 상호배제를 만족시키지만 문제점이 있다.

  • 임계구역 진입을 교대로 진입해야 하고, 빠른 프로세스는 느린 프로세스의 속도에 의존한다.
  • 한 프로세스가 임계 구역 내에서 중지된다면 다른 프로세스도 수행을 할 수 없다.
  • 공유 변수 설정에 따라 시작되는 순서가 결정된다.

 

➤  2단계 Mutual Exclusion Algorithm

  • 두 개의 공유 변수(p0_inside, p1_inside)를 이용하여 상호배제를 해결하고자 한다.

Pseduo Code

program mutex2;
boolean p0_inside, p1_inside;

p0(){ 
    while(true){
        while(p1_inside == TRUE) 
        ;
        p0_inside = TRUE; //p0이 임계구역 진입시도
        critical_section
        p0_inside = FALSE; //p1에게 진입순서 양보
        remainder section 
    }
}
p1(){ 
    while(true){
        while(p0_inside == TRUE) 
        ;
        p0_inside = TRUE; //p1이 임계구역 진입시도
        critical_section
        p0_inside = FALSE; //p0에게 진입순서 양보
        remainder section 
    }
}
//main
    p0_inside = false, p1_inside = false;
    parbegin
     p0();
     p1();
    Parend

2개의 프로세스가 병행하면서 한 줄씩 수행했을 때 문제점이 생긴다.

  • 동시에 임계구역 진입이 가능한 경우가 발생하여 상호배제가 보장되지 않는다.
  • 1단계와 다르게 순서가 정해져 있지 않다. (p0이 먼저 들어와도 되고, p1이 먼저 들어와도 된다.)

 

➤  3단계 Mutual Exclusion Algorithm

  • 2단계의 문제점 해결

Pseduo Code

program mutex3;
boolean p0_inside, p1_inside;

p0(){ 
    while(true){
        p0_inside = TRUE; 
        while(p1_inside == TRUE) 
        ;
        critical_section
        p0_inside = FALSE; 
        remainder section 
    }
}
p1(){ 
    while(true){
        p1_inside = TRUE; 
        while(p0_inside == TRUE) 
        ;
        critical_section
        p1_inside = FALSE; 
        remainder section 
    }
}
//main
    p0_inside = false, p1_inside = false;
    parbegin
     p0();
     p1();
    Parend

while문 수행 이전에 자신의 플래그(px_inside)를 true로 미리 변경한다.(상호배제는 보장) 하지만 교착상태가 발생(두 프로세스가 수행을 못하는 상태)할 위험이 있다.

  • 두 프로세스가 while문 이전에 차례대로 px_inside를 각각 true로 변경하면, 내부의 while문에서 각각 무한 루프를 돌게 된다.
  • while(p1_inside == TRUE)과 while(p0_inside == TRUE)

 

➤  4단계 Mutual Exclusion Algorithm

  • 1단계와 3단계 알고리즘을 결합한 것이다.
  • 3개의 공유 변수(p0_inside, p1_inside, processnumber)를 이용한다.

Pseduo Code

program mutex3;
boolean p0_inside, p1_inside;
var processesnumber;

p0(){ 
    while(true){
        p0_inside = TRUE;
        processesnumber = 1;
        while(p1_inside == TRUE and processesnumber == 1) 
        ;
        //p0의 진입여부 확인
        critical_section
        p0_inside = FALSE; 
        remainder section 
    }
}
p1(){ 
    while(true){
        p1_inside = TRUE; 
        processesnumber = 0;
        while(p0_inside == TRUE and processesnumber == 0) 
        ;
        //p1의 진입여부 확인
        critical_section
        p1_inside = FALSE; 
        remainder section 
    }
}
//main
    p0_inside = false, p1_inside = false;
    parbegin
     p0();
     p1();
    Parend

3단계 상호 배제 알고리즘의 교착상태 발생 위험을 제거하고, 상호배제도 만족시킨다.

 

(4) Synchronization by Hardware (하드웨어에 의한 동기)

하드웨어적인 임계구역 문제 해결

  • 단일 프로세서(CPU) 시스템에서 임계구역 문제를 해결하기 위해서는 공유변수가 변경되는 동안 다른 프로세스가 공유변수에 접근하지 못하도록 혹은 인터럽트 발생을 허용하지 않도록 설정하면 된다.
  • 더 이상 분할이 불가능한 특별한 하드웨어 명령인 *TestAndSet(targer)을 이용하여 임계구역 문제를 해결하고자 한다. (하드웨어 칩 이용)

*TestAndSet : 일단 수행이 시작되면 인터럽트 없이 모두 끝마쳐야 하는 하드웨어적 명령문으로, 공유변수 부분을 하드웨어 칩으로 구현한다. 다시 말해서 TestAndSet이 수행되는 동안 다른 것이 수행되지 않는다.

 

Pseudo Code

boolean TestAndSet(boolean & target){
    boolean temp = target;
    target = true;
    return temp;
    //target이 false인 경우, temp = false로 설정, false 반환
}
testandsetexample(){
    boolean lock;
    
    p0(){
        while(true){
            while(TestAndSet(lock))
            ;
            critical section
            lock = false;
            remainder section
        }
    }
    p1(){
        while(true){
            while(TestAndSet(lock))
            ;
            critical section
            lock = false;
            remainder section
        }
    }
    lock = false;
    parbegin
    p0();
    p1();
    parend
}

 

(5) Semaphore(세마포어)

✔  세마포어(임계구역에서 프로세스들의 동기화 방법)정의

  • 프로세스 동기화 문제 해결을 위한 두 가지 연산(P, V)이 필요하다.
    P : 네덜란드어로 검사(Proberen)를 나타내며, 프로세스를 대기시켜서 동작으로 임계구역에 진입하기 위한 연산(wait), S값을 감소시킨다. (공유자원을 가져간다)
    V : 네덜란드어로 증가(Verhogen)를 나타내며, 대기 중인 프로세스를 깨우기 위해 신호를 보내는 동작으로 임계구역에서 나오기 위한 연산(signal), S값을 증가시킨다. (공유자원을 반납한다)
    S : 세마포어를 나타내며 표준 단위 연산 P와 V에 의해서만 접근되는 정수 변수로, 이 S값을 이용하여 프로세스들의 임계구역 접근을 제어한다.

 

세마포어 사용법과 P연산 및 V연산 정의

while(true){
    P(S);
    임계구역
    while S <= 0 do no-operation; // S = 0 일 때 또 다른 프로세스가 공유자원을 요청하면 음수값을 방지
    S = S - 1;
    V(S);
    잔류구역
    S = S + 1;
}

 

 

✔  세마포어를 이용한 생산자/소비자(데이터의 생산자/소비자) 문제 해결

  • 공유변수 semaphore mutex = 1; -> 버퍼 접근에 대한 상호 배제를 위한 세마포어
  • 공유변수 semaphore empty = n; -> 버퍼에 비어 있는 항목의 개수를 위한 세마포어
  • 공유변수 semaphore full = 0; -> 버퍼에 채워져 있는 데이터의 개수를 위한 세마포어
  • 생산자 : 버퍼에 데이터를 넣기 위해 버퍼의 비어 있는 항목의 수(empty)를 1감소시킨다.
    • empty값이 0이면 프로세스가 블록된다. 다시 말해 생산자가 버퍼에 접근하지 못한다.
  • 소비자 : 버퍼에 채워진 데이터의 개수를 나타내는 full값을 1감소시킨다.
    • full값이 0이면 프로세스가 블록된다. 다시 말해 소비자가 버퍼에 접근하지 못한다.

 

 

✔  세마포어를 이용한 데이터 읽기/쓰기 문제 해결

  • 공유변수 semaphore wrt = 1; -> 쓰기 프로세스 접근 시 배타적 사용을 위한 세마포어
  • 공유변수 semaphore mutex = 1; -> readcount 변수의 상호 배제를 위한 세마포어
  • int readcount = 0; -> 읽기 프로세스의 개수 (초기 값은 0이다)
  • wrt 세마포어는 쓰기 프로세스가 임계구역에 있을 경우, 다른 쓰기나 읽기 프로세스가 임계구역에 접근하지 못하도록 한다.
  • P(wrt) : 읽기 프로세스가 1개 이상인 경우 쓰기 프로세스가 실행되지 못하도록 하다.
  • readcount-- : 읽기 프로세스가 읽기를 마치고 빠져 나오는 경우에 자신을 제외한 다른 읽기 프로세스가 존재하는 경우에는 그냥 빠져 나온다.
  • V(wrt) : 자신이 마지막 읽기 프로세스인 경우에는 쓰기 프로세스의 임계구역 진입을 허용한다.

 

(6) Monitor

개요 및 정의

  • 순차적으로만 사용할 수 있는 특정 공유자원이나 공유자원 그룹을 할당하는데 사용된다.
  • 데이터 및 프로시듀어를 포함하는 병행성 구조이다.
  • 공유자원에 접근하고자 하는 프로세스는 반드시 특정 모니터의 진입부(entry)를 호출해야 한다.
  • 이미 사용 중인 모니터에 들어가려고 하는 다른 프로세는 반드시 대기해야 한다.

 

모니터

  • 세마포어의 P, V연산이 프로그램 전체에 퍼져 있어 이들의 연산이 미치는 영향을 전체적으로 파악하기 쉽지 않아 프로그램 작성이 어려운 단점을 극복하기 위해 모니터 방법이 필요하다.
    • 세마포어와 비슷한 기능을 하지만 제어하기가 용이하다.
  • 프로그래밍 언엥서 지원한다. 즉, 프로그램 라이브러리 형태로 지원한다.
  • 데이터와 이들 데이터를 처리하는 프로시듀어의 집합이다. (객체지향 개념)
  • 모니터 내의 데이터는 모니터 내부에 의해서만 접근이 가능하므로 모니터 외부의 프로세스는 접근할 수 없어 정보 은폐(Informaiton Hiding)라고도 한다. (객체지향 개념)

 

✔ 모니터 사용

모니터 구조

  • 하나의 프로세스가 모니터 내부에 머물러 있으면, 다른 프로세스의 진입을 허용할 수 없으므로 다른 프로세스는 모니터 밖에서 signal()이 있기까지 대기해야 한다.
  • 동기화 기법이 필요하다면 프로그래머는 조건 변수를 선언하여 해결한다.
  • condition x에 대하여 x.wait()와 x.signal()이 이용된다.
  • 조건 변수에서 호출될 수 있는 연산은 wait와 signal이다.

 

연산 : x.wait() or wait(x)

x.wait() or wait(x) 연산을 호출하는 프로세는 다른 프로세를 다음 연산이 호출될 때까지 중단시킨다. 세마포어의 P연산과 유사하고, x는 세마포어의 S와 유사하다.


연산 : x.signal() or signal(x)
x.signal() or signal(x)은 중단된 다른 프로세스를 재개시킨다. 세마포어의 V연산과 유사하다.

 

환형 버퍼에서 생산자/소비자 문제에 대한 모니터 사용 예시

 

(7) Message

  • 프로세스 간의 통신 및 동기화에 적합한 비교적 단순한 메커니즘이다.
  • 공유변수를 이용한 방법은 공유변수에서 병목현상 문제가 발생할 수 있고, 공유변수 파괴 시 시스템 성능의 현저한 저하 문제가 발생하여 이에 프로세스 간 직접 통신을 통하여 상호 간에 순서를 정하여 동기화를 해결하고자 한다.
  • 메시지의 정의는 송신측 프로세스와 수신측 프로세스 간에 교환될 수 있는 정보의 집합이다.
  • 분산 OS에서 메시지 메커니즘의 사용이 보편화 되어 있다.

 

메시지 형식
송신측 및 수신측 식별자(identifier)길이, 형식(type), data로 구성된다.


메시지 발생 시 고려사항
naming 문제 : 메시지 교환에 관계되는 해당 프로세스들이 상대 프로세스를 설정하는 방법을 결정한다.
직접 네이밍과 간접 네이밍 방식의 두 가지 형태가 존재한다.

 

➤  직접 Naming Method

  • 송신측(sender)이 특정 수신측(recipient)을 설정해야 하고, 반대로 메시지 수신을 희망하는 수신측은 송신측을 설정한다.
  • 일대일 통신 관계로 인하여 보다 안전하고 확실한 메시지 통신이 가능하다.
process A;
..
send(B, message); //A가 B에게 메시지를 보내겠다.
..
process B;
..
receive(A, message); //B가 A로부터 메시지를 받겠다.
..

 

 

➤  간접 Naming Method

  • 메시지가 특정 목적만을 위하여 사용되는 영역에 송신되고, 그 영역에서 다른 메시지도 수신하는 방식으로 특정 영역을 우편함(mailbox)이라고 부른다.
  • 모든 프로세스 간의 메시지 교환은 이 우편함을 통하여 수행된다.
  • 송신측과 수신측 간에 일대일, 일 대 다수, 다수 대 일, 다수 대 다수의 통신 관계가 가능하다는 점에서 매우 유용하다.
process A;
..
send(mailbox1, message); 
..
process B;
..
receive(mailbox1, message);
..

 

 

✔  메시지 방식에서의 고려해야 할 사항

복사(Copying) 문제

  • 전체 메시지를 수신측의 주소 공간에 복사하여 두거나, 또는 두 프로세스 간의 메시지에 대한 포인터를 단순히 전달함으로써 해결한다.
  • 한 프로세스에서 오류가 발생하더라도 이로 인하여 메시지의 지역 복사본만이 손상된다.
  • 송신측 프로세스의 버퍼에 메시지 복사, 수신측 프로세스의 버퍼에 메시지 다시 복사한다.
  • 단점은 메시지 복사가 기억장치와 CPU의 사이클을 낭비한다.

 

버퍼링(Buffering) 문제

  • 수신을 위한 준비가 되어 있지 않을 경우 송신측은 메시지를 일단 버퍼에 송신(저장)하고 나중에 수신측이 준비되면 그 때 전송된다.
  • 비동기적 통신을 가능하게 하기 위해서는 버퍼링 방식이 필요하다.
  • 수신측 상황에 관계없이 자신의 실행을 계속할 수 있는 과정을 “set and forget” 운영이라 하며, 이는 시스템 병행성의 정도를 향상시킨다.

 

길이(Length) 문제

  • 메시지의 길이를 고정적으로 할 것인지 또는 가변적으로 할 것인지를 결정한다.
  • 고정길이 메시지: 구현이 용이하나, 버퍼의 크기에 비하여 메시지가 작을 경우 버퍼의 낭비를 초래하며, 반대로 메시지가 클 경우에는 메시지를 분할하여 전송해야 하는 문제점이 있다.
  • 가변길이 메시지: 동적으로 버퍼를 생성하는 것으로 구현이 복잡하기는 하나 높은 적응력을 가진다.

'운영체제' 카테고리의 다른 글

[OS] 09. 정보 보호 및 보안  (0) 2023.10.16
[OS] 08. 교착상태 (Deadlock)  (0) 2023.10.16
[OS] 06. 파일 시스템  (0) 2023.10.16
[OS] 05. 디스크 스케줄링  (0) 2023.10.16
[OS] 01. 운영체제 소개 (2)  (0) 2023.10.16