IPC(Inter Process Communication)
IPC는 프로세스 간 통신이라는 뜻으로 프로세스들 사이에 서로 데이터를 주고받는 행위 또는 방법이나 경로를 뜻한다.
프로세스는 독립적으로 실행되기 때문에 다른 프로세스에 영향을 받지 않는다.
반대로 스레드는 프로세스 안에서 자원을 공유하므로 영향을 받는다.
이런 상황에서 프로세스 간의 통신이 필요한 상황이 있을 것이다.
그런 경우에 이를 가능하게 해주는 것이 바로 IPC 통신이다.
프로세스는 커널이 제공하는 IPC 설비를 이용해 프로세스 간 통신을 할 수 있게 된다.
커널(Kernel)
운영 체제의 핵심적인 부분으로 운영 체제의 핵심 기능 및 자원 관리를 담당하며, 하드웨어와 응용 프로그램 간의 통신을 중재합니다. 대표적인 커널로 linux 커널, Window 커널, macOS 커널 등이 있다.
IPC에도 몇 가지 메커니즘이 존재하는데 이에 대해 알아보자.
- 익명 파이프 (Unnamed Pipe) : 두 개의 프로세스를 연결하는 데 하나의 프로세스는 데이터를 쓰기만 하고, 다른 하나는 데이터를 읽기만 할 수 있다. 한쪽 방향으로만 통신이 가능한 반이중 통신이라고도 부른다.
- 이름이 있는 파이프 (Named Pipe 또는 FIFO) : 통신할 프로세스를 명확히 알 수 있는 경우(ex) 부모 자식 프로세스 통신)에 사용한다. Named Pipe도 익명 파이프와 동일하게 단방향 통신 메커니즘을 갖고 있다.
- 메시지 큐 (Message Queue) : 프로세스 간에 메시지를 비동기적으로 전달하는 데 사용된다. 메시지 큐를 통해 메시지를 보내고 받는 프로세스는 독립적으로 실행된다. 파이프와 다른 점은 데이터의 흐름이 아니라 메모리 공간이다.
- 공유 메모리 (Shared Memory) : 데이터 자체를 공유하도록 지원하는 설비이다. 프로세스가 공유 메모리 할당을 커널에 요청하면, 커널은 해당 프로세스에 메모리 공간을 할당해 주고 이후 모든 프로세스는 해당 메모리 영역에 접근할 수 있게 된다. 중개자 없이 곧바로 메모리에 접근할 수 있어서 IPC 중에 가장 빠르게 작동한다.
- 소켓 (Socket) : 네트워크 소켓 통신을 통해 데이터를 전송하는 데 사용되며 IPC의 확장된 형태이다. 클라이언트와 서버가 소켓을 통해서 통신하는 구조이다.
IPC는 다양한 운영 체제에서 지원되며, 프로세스 간 통신 및 협력을 허용하여 복잡한 응용 프로그램 및 시스템을 개발하는 데 중요한 역할을 한다.
이러한 IPC 통신에서 프로세스 간 데이터를 동기화하고 보호하기 위해 사용하는 게
세마포어(Semaphore) & 뮤텍스(Mutex)이다.
공유된 자원에 한 번에 하나의 프로세스만 접근시킬 때 사용한다.
임계 구역
세마포어와 뮤텍스를 이해하려면 임계 구역(Critical Section)을 알아야 한다.
임계 구역(Critical Section)은 다중 프로세스 또는 다중 스레드 환경에서 데이터를 공유하며 수행될 때, 각 프로세스에서 공유 데이터를 접근하는 프로그램 코드 부분이다. 다른 말로는 공유 변수 영역이라고 한다.
공유 데이터를 여러 프로세스가 동시에 접근할 때 잘못될 결과를 만들 수 있기 때문에 충돌을 방지하고 데이터 무결성을 유지하기 위한 메커니즘이다.
임계 구역은 다음과 같은 3가지 특성을 갖고 있다.
- 상호 배제(mutual exclusion) : 한 프로세스가 임계 구역에 들어가 있으면 다른 프로세스는 들어갈 수 없다.
- 한정 대기(bounded wating) : 프로세스가 자기의 임계구역에 진입하려는 요청을 한 후부터 그 요청이 허용될 때까지 다른 프로세스들이 그들 자신의 임계구역에 진입하도록 허용되는 횟수에 한계가 있어야 한다.
- 진행의 융통성(progress flexibility) : 자기의 임계구역에서 실행되는 프로세스가 없고 그들 자신의 임계구역으로 진입하려고 하는 프로세스들이 있다면, 나머지 구역에서 실행 중이지 않은 프로세스들만 다음에 누가 그 임계구역으로 진입할 수 있는지를 결정하는 데 참여할 수 있으며, 이 선택은 무한정 연기될 수 없다.
이러한 특성은 경쟁 조건(Race Condition)과 같은 문제를 방지하고 공유 자원을 안정할 수 있도록 한다.
경쟁 조건(Race Condition)은 두 프로세스가 서로 경쟁하여 데이터에 손상을 일으키는 경우를 말한다.
이러한 임계 구역을 만족하기 위해서 구현하는 방법들이 세마포어와 뮤텍스이다.
세마포어(Semaphore)
세마포어는 다중 프로세스 또는 다중 스레드 환경에서 동기화와 상호 배제를 관리하기 위한 동기화 도구 중 하나이다.
세마포어는 데이터나 자원에 대한 접근을 조절하는 데 사용된다.
세마포어 P, V 연산
P : 임계 구역 들어가기 전에 수행 ( 프로세스 진입 여부를 자원의 개수(S)를 통해 결정)
V : 임계 구역에서 나올 때 수행 ( 자원 반납 알림, 대기 중인 프로세스를 깨우는 신호 )
구현 예시
procedure P(S) --> 최초 S값은 1임
while S=0 do wait --> S가 0면 1이 될때까지 기다려야 함
S := S-1 --> S를 0로 만들어 다른 프로세스가 들어 오지 못하도록 함
end P
--- 임계 구역 ---
procedure V(S) --> 현재상태는 S가 0임
S := S+1 --> S를 1로 원위치시켜 해제하는 과정
end V
이를 통해 한 프로세스가 P 혹은 V를 수행하고 있는 동안 프로세스가 인터럽트 당하지 않게 된다.
세마포어는 크게 두가지 유형으로 나뉜다.
- 이진 세마포어 (Binary Semaphore): 값이 0 또는 1만 가질 수 있는 세마포어로, 주로 임계 구역의 이진 상태를 관리하는 데 사용됩니다. 이러한 이진 세마포어를 뮤텍스(Mutex)라고도 부른다.
- 카운팅 세마포어 (Counting Semaphore): 값이 양수 또는 음수가 될 수 있는 세마포어로, 여러 프로세스나 스레드가 동시에 접근할 수 있는 자원의 수나 작업 허용량을 관리하는 데 사용된다.
세마포어를 사용하면 공유자원에 대한 안전한 접근을 조절하고, 다중 프로세스 또는 스레드 간의 동기화 문제를 해결할 수 있지만 올바르게 사용하려면 주의 깊은 설계와 구현이 필요하다.
뮤텍스(Mutex)
뮤텍스는 mutual exclusion의 약자로 상호 배제라는 뜻이다. 임계 구역을 가진 스레드들의 실행 시간이 서로 겹치지 않고 단독으로 실행되게 하는 기술을 말한다.
해당 접근을 조율하기 위해 lock과 unlock을 사용한다
lock은 현재 임계 구역에 들어갈 권한을 얻어오며, unlock은 현재 임계 구역을 모두 사용했음을 알린다.
뮤텍스는 상태가 0,1로 이진 세마포어라고도 불린다.
뮤텍스는 일반적으로 단일 소유권을 가지며, 잠긴 상태에서 다른 스레드 또는 프로세스가 잠금을 얻을 수 없다. 이로써 공유 자원에 대한 동시 액세스를 방지할 수 있다.
뮤텍스는 다른 스레드가 뮤텍스를 이미 잠갔을 경우, 새로운 스레드는 뮤텍스가 해제될 때까지 대기한다. 이러한 특성을 통하여 경쟁 조건(Race Condition)을 방지하고 공유 자원의 일관성 유지에 도움을 준다.
lock과 unlock을 사용한 이진 세마포어 알고리즘 외에도 여러가지가 있다.
1. 데커 알고리즘 : flag와 turn이라는 변수로 임계 영역에 들어갈 프로세스나 스레드를 결정하는 방식이다.
flag는 프로세스 중 누가 임계 영역에 진입할 것인지를 나타내는 변수이며,
turn은 누가 임계 구역에 들어갈 차례인지 나타내는 변수이다.
while(true) {
flag[i] = true; // 프로세스 i가 임계 구역 진입 시도
while(flag[j]) { // 프로세스 j가 현재 임계 구역에 있는지 확인
if(turn == j) { // j가 임계 구역 사용 중이면
flag[i] = false; // 프로세스 i 진입 취소
while(turn == j); // turn이 j에서 변경될 때까지 대기
flag[i] = true; // j turn이 끝나면 다시 진입 시도
}
}
}
// ------- 임계 구역 ---------
turn = j; // 임계 구역 사용 끝나면 turn을 넘김
flag[i] = false; // flag 값을 false로 바꿔 임계 구역 사용 완료를 알림
2. 피터슨 알고리즘 : 데커와 유사하지만 상대방 프로세스,스레드에게 진입 기회를 양보하는 것에 차이가 있는 알고리즘
while(true) {
flag[i] = true; // 프로세스 i가 임계 구역 진입 시도
turn = j; // 다른 프로세스에게 진입 기회 양보
while(flag[j] && turn == j) { // 다른 프로세스가 진입 시도하면 대기
}
}
// ------- 임계 구역 ---------
flag[i] = false; // flag 값을 false로 바꿔 임계 구역 사용 완료를 알림
3. 제과점(Bakery) 알고리즘 : 여러 프로세스,스레드에 대한 처리가 가능한 알고리즘이다. 가장 작은 수의 변호표를 가지고 있는 프로세스가 임계 구역에 진입한다.
while(true) {
isReady[i] = true; // 번호표 받을 준비
number[i] = max(number[0~n-1]) + 1; // 현재 실행 중인 프로세스 중에 가장 큰 번호 배정
isReady[i] = false; // 번호표 수령 완료
for(j = 0; j < n; j++) { // 모든 프로세스 번호표 비교
while(isReady[j]); // 비교 프로세스가 번호표 받을 때까지 대기
while(number[j] && number[j] < number[i] && j < i);
// 프로세스 j가 번호표 가지고 있어야 함
// 프로세스 j의 번호표 < 프로세스 i의 번호표
}
}
// ------- 임계 구역 ---------
number[i] = 0; // 임계 구역 사용 종료
'Computer Science > Operating System(OS)' 카테고리의 다른 글
페이징 & 세그먼테이션 (0) | 2023.09.05 |
---|