프로세스를 종료하면 사용하던 자원은 운영체제가 되찾아간다. 그러나 프로세스의 종료 상태가 저장되는 프로세스 테이블의 해당 항목은 부모 프로세스가 wait()를 호출할 때 까지 남아있게 된다. 이런 프로세스를 좀비 프로세스라고 칭한다.
모든 프로세스는 종료시 아주 짧은 상태의 좀비 프로세스가 된다. 운영체제에 곧 반환된다.
부모 프로세스가 wait()대신 종료를 해버리면 자식 프로세스는 고아 프로세스가 된다.
Linux에서는 고아프로세스의 부모를 init으로 지정함으로써 이 문제를 해결한다.
IPC; Interprocess communication
프로세들은 서로 협력할 수 있다.
다른 프로세스와 통신을 허용하는 환경을 제공하는 이유
정보 공유 Information sharing : 여러 사용자가 동일한 정보를 원할 수 있다. 병행적으로 접근할 수 있어야 한다.
계산 가속화 Computation speedup : 복수개의 코어처리를 가진 경우 서브태스크로 나눠 작업을 병렬로 실행할 수 있어야 한다.
모듈성 Modularity : 시스템 기능을 별도의 프로세스 또는 스레드로 나눠 모듈식 형태로 시스템을 구성하기 원할 수 있다.
편의성 Convenience : 사용자들은 다수의 태스크를 병렬로 가질 수 있다.
협력적인 프로세스들은 데이터와 정보를 교환할 수 있는 Interprocess communication 기법을 필요로 한다.
프로세스간 통신에는 공유 메모리와 메시지 전달 두가지 모델이 있다. 운영체제는 두가지를 모두 구현한다.
일반적으로 메시지 전달이 더 나은 성능을 보인다
공유 메모리는 공유데이터가 여러 캐시사이에서 이주하기 때문에 캐시 일관성 문제로 성능 저하가 발생한다.
공유 메모리 시스템
공유메모리 영역은 공유 메모리 세그먼틀르 생성한느 프로세스의 주소 공간에 위치한다.
공유메모리 세그먼트를 이용하고자 하는 다른 프로세스들은 이 세그먼트를 자신의 주소공간에 추가해야 한다.
일반적으로 하나의 주소 공간에 두 프로세스가 접근하는것을 허용하지 않기 때문에 제약을 해제하는 작업이 필요하다.
데이터 형식과 위치는 프로세스에 의해 결정된다. (운영체제 소관X)
생산자 프로세스와 소비자 프로세스가 병행으로 실행되게 하려면 공유 메모리 모델이 있다.
정보가 오가는 항목에 버퍼가 있어야 한다.
생산자와 소비자가 동기화 되어야 있지도 않은 항목을 소비하지 않을 수 있다.
무한버퍼 : 버퍼 크기에 제한이 없어 생산자는 항상 새로운 항목을 생산할 수 있으나 소비자는 새로운 항목을 기다려야 할 수도 있다.
유한버퍼 : 버퍼의 크기가 고정되어 있고 소비자는 반드시 대기 해야하고 모든 버퍼가 채워져 있을때는 생산자가 대기해야 한다.
메시지 전달 시스템
공유메모리 외에 협력하는 방법으로 메시지 전달 설비를 통해 프로세스간 통신 수단을 운영체제가 제공한다.
메시지 전달 방식은 동일한 주소 공간을 공유하지 않고도 프로세슫르이 통신을 하고, 그들의 동작을 동기화할 수 있도록 허용하는 기법을 제공한다.
메시지 전달 방식은 분산환경에서 유용하다.
메시지 전달 시스템은 최소한 send()와 receive()가 존재한다.
통신하기 위해 Communication link가 반드시 필요하다.
send()와 receive()를 구현하는 방법
직접 또는 간접 통신
동기식 또는 비동기식 통신
자동 또는 명시적 버퍼링
직접 통신
통신을 원하는 각 프로세스의 쌍들 사이에 연결이 자동적으로 구축된다. 프로세스들은 통신하기 위해 서로의 id만 알면 된다.
연결은 두 프로세스 사이에서만 이루어진다.
하나의 쌍에 하나의 연결만 존재한다.
주소 방식에서 대칭성을 보인다.
프로세스 지정으로 인해 프로세스 식별자를 바꾸면 지정된 다른 부분을 모두 검사해야 한다.
간접 통신
한쌍의 프로세스들 사이의 연결은 이들 프로세스가 공유 메일박스를 가질때만 구축된다.
연결은 두개 이상의 프로세스들과 연관될 수 있다.
통신하고 있는 각 프로세스들 사이에는 다수의 서로 다른 연결이 존재할 수 있다.
각 연결은 하나의 메일 박스에 대응한다.
동기화
프로세스는 send()와 receive() 원형을 호출해 서로 통신한다. 각 원형을 구현하기 위한 설계 옵션이 있다.
메시지 전달은 blocking과 non-blocking방식으로 전달된다.
동기식 송신 : 송신하는 프로세스는 메시지가 수신 프로세스 또는 메일 박스에 의해 수신될 때 까지 블로킹 한다.
비동기식 송신 : 송신하는 프로세스가 메시지를 보내고 작업을 재시작한다.
동기식 수신 : 수신자는 메시지가 도착할 때 까지 블로킹 된다.
비동기식 수신 : 수신자는 유효한 메시지를 받거나 널을 받는다.
send()와 receive()간에 다른 조합도 가능하다.
send()와 receive()가 모두 동기식일때 둘 간에 랑데뷰를 이룬다.
CS 통신
클라이언트-서버 환경에서 사용할 수 있는 세가지 다른 통신 전략이 있다.
소켓, RPC, 파이프
Socket
소켓은 통신의 endpoint를 뜻한다.
네트워크를 통해 통신하는 한 쌍의 프로세스는 프로세스당 하나씩, 한쌍의 소켓이 필요하다.
각 소켓은 IP와 port로 식별된다.
public class DataServer {
public static void main(String[] args) {
try{
ServerSocket sock = new ServerSocket(6013);
while(true){
Socket client = sock.accept();
PrintWriter pout = new PrintWriter(client.getOutputStream(), true);
pout.println(new Date().toString());
client.close();
}
}
catch (IOException e){
System.err.println(e);
}
}
}
public class DataClient {
public static void main(String[] args) {
try{
Socket sock = new Socket("127.0.0.1", 6013);
InputStream in = sock.getInputStream();
BufferedReader bin = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = bin.readLine()) != null) {
System.out.println(line);
sock.close();
}
}
catch (IOException e){
System.err.println(e);
}
}
}
소켓은 바이트 스트림 기반이기 때문에 해석하는것은 서버와 클라이언트의 몫이다.
RPC; 원격 프로시저 호출
RPC는 두 시스템 사이에 통신하기 위해 프로시저 호출 기법을 분리해 생각하기 위한 방편이으로 IPC기반으로 만들어진다.
RPC는 IPC와 달리 전달되는 메시지가 구조화 되어있고 데이터의 패킷 수준을 넘어선다.
각 메시지는 원격지 포트에서 리스닝 중인 RPC데몬의 주소가 지정되어있고 함수, 매개변수가 포함되어 있다.
클라이언트와 서버의 데이터 표현방식이 빅엔디안과 리틀엔디안이 다를 경우에 대비해 XDR이라는 중립적인 표현방식으로 변환해 전송한다.
호출의 semantic이 실패하거나 중복되는것을 방지 하기 위해 정확히 한번만 처리되도록 보장해야 한다.
RPC는 분산 파일 시스템을 구현하는데 유용하다.
파이프
파이프는 두 프로세스가 통신할 수 있게 하는 전달자다.
통신에 여러 제약이 있다.
고려해야 하는 부분
파이프가 단방향 또는 양방향을 허용하는가?
양방향을 허용한다면 반이중인가? 전이중인가?
부모-자식 같은 특정 관계가 존재해야 하는가?
네트워크 통신이 가능한가? 같은 시스템 내에서만 가능한가?
일반 파이프
생산자-소비자 형태고 두 프로세스간의 통신을 허용한다.
단방향이다.
파이프를 생성한 프로세스 이외에는 접근할 수 없다.
통상 부모 프로세스가 파이프를 생성하고 fork한 자식 프로세스와 통신하기 위해 사용된다.
지명 파이프
지명 파이프는 양방향으로 통신이 가능하다
부모-자식 관계도 필요 없다.
지명 파이프가 구축되면 여러 프로세스들이 이를 사용해 통신할 수 있다.
두 프로세스는 동일한 시스템 내에 존재해야한다.
UNIX에서는 지명파이프를 FIFO라고 부른다.
실제 상황에서의 파이프
파이프는 한 명령어의 출력이 두번째 명령어의 입력으로 사용되는 경우, 명령어 라인 환경에서 자주 사용된다. ls는 디렉토리 목록을 생성한다. 특히 긴 디렉토리 목록의 경우 출력은 여러 화면에 걸쳐 스크롤 될 것이다. more 명령어는 한번에 한 화면 단위로 출력되도록 출력을 관리한다. ls와 more의 명령어 사이에 파이프를 구축하면 ls의 출력이 more의 입력으로 전달되도록 하여 사용자가 긴 디렉토리 목록을 한 화면 단위로 볼 수 있게 한다.