반응형
250x250
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

짧은코딩

IPC(Inter Process Communication)와 사례연구 본문

학교/운영체제

IPC(Inter Process Communication)와 사례연구

5_hyun 2021. 10. 7. 12:41
  • IPC

 

-프로세스간 통신(IPC)

1. 프로세스내부 데이터 통신

2개 이상의 스레드간 데이터통신(메모리변수 이용)

전역변수, 파일공유를 통한 데이터전달

 

2. 프로세스간 데이터 통신

동일 컴퓨터내 프로세스간 통신, 운영체제에 의한 통신

shared memory, pipe 등 이용

 

3. 네트워크를 이용한 원격 데이터 통신

네트워크(인터넷)간의 프로세스간 데이터전송(send, receive)

소켓, PRC과 같은 네트워크 프로토콜 이용, 인터넷을 통한 원격 연결

 

-(프로세스 내부) 전역 변수를 이용한 통신방식


프로세스 내부에서 이뤄진다.
전역 데이터를 통해서 주고 받는다.


스레드를 생성하고 일거리를 준다.
fom1to2, from2to1은 공유자원이다.
스레드 1, 2가 동시에 돌면서 변수를 저장한다.

 

-프로세스 간의 파일공유를 이용한 방식


프로세스 1이 com.txt 만들고 Test를 wirte한다
그러면 프로세스2가 read한다


결국 프로세스1이 프로세스2에게 test로 넘겨줬다.
생산자 소비자 구조와 비슷하다 


파일을 사용하려면 반드시 open 해야한다.
프로세스1 write
프로세스2 read
open을 했으면 반드시 close 해야한다.
open하면 PCB가 만들어진다. PCB에 오픈 파일 정보 공간이 생긴다. 만약 공간이 부족하면 오픈 실패가 난다. 그래서 close를 반드시 해줘서 PCB 내에 공간을 확보해야한다.

 

-동일 컴퓨터내의 프로세스간 통신방법(Shared Memory, Message passing, File Sharing)


a, 프로세스 A와 프로세스 B가 있다 shared memory는 A도 B도 아니다. A와 B는 shared memory를 통해 자원을 공유하고 통신한다.

 

b, message라는 포멧을 만든다. 커널내부에 message queue 터널이 운영하는 공간이다. 만약  B가 A에게 보내고 싶은 메시지가 있다. 그러면 B는 메시지큐에다가 m0, m1 등등으로 저장하고 A가 읽어오는 방식이다. fifo이다.
message queue를 파일에서 구현한게 pipe이다.

 

-(프로세스 간) 파이프를 이용한 통신방법

프로세스 A, B가 있다 Pipe를 통해 데이터를 주고 받는다.
파이프는 사실 파일이라고 보면된다. 하지만 프로세스 입장에서는 파이프로 보고 이것을 통해 데이터를 주고 받는다. 파이프 내부를 뜯어보면 결국 파일이다.
A가 보내고 싶으면 파이프에 write하고 B는 read한다.
B가 보내고 싶으면 그 목적의 파이프2를 만들고 write, A는 read하면된다.

A, B를 협력프로세스해서 병행처리한다. 즉 고성능 프로그램을 만들 수 있다.
파이프는 운영체제에서 제공하는 기능
파이프도 특수 파일로 부른다.

 

-(원격으로) 소켓을 이용한 프로세간 통신방법

원격 네트워크
소켓을 이용한 방식 IPC
프로세스 A, B가 있다. A는 서울, B는 la에 있다하면 인터넷을 통해 데이터 주고받을수있다.
그 중 소켓은 네트워크 기능을 이용할 수 있는 특수 파일이다.
특수파일 하나를 만들어서 주거니 받거니 하는 것이다.
소켓과  pipe, shared memory, message queue 모두 무언가 통해서 파일을 주고 받는다.
파일형태로 유지하면 통신 시킬 수 있다. 프로그램 입장에선 어떤 파일 특수파일이든 write, read로 같다.
그러다 보니 소켓이든 파이프이든 프로그램 입장에선 똑같이 IPC 할 수 있다.

 

소켓을 디테일하게 본다는건 네트워크 범주이다.
application A가 있다고 치자
다른 상대 B에게 소켓, 네트워크를 통해 보내고자한다.

소켓은 파일 개념이라 read, wirte하여 각 프로세스가 처리한다.
소켓을 이용하고 밑에 소켓 부분에서 read, write한다.

 

A가 소켓 '가'에게 write를 했다 -> 소켓과 연결되어진 TCP 계층으로 데이터를 보내달라고 전송한다.

이걸 받은 TCP 계층은 밑에 있는 IP 계층에게 전송해달라고 요청한다.

IP 계층은 밑에 있는 LAN 카드를 통해 LAN 선으로 나간다.

그치만 프로세스 A 입장에서는 LAN을 알 필요가 없다. 따라서 파일 다루듯이 쉽게 쓸 수 있다.

 

네트워크에선 항상 c-s구조이다.
클라이언트가 서버에게 뭐가 필요하다는 데이터를 요청하면 서버는 데이터를 넘겨준다.

서버
1. 서버는 소켓을 만들어야한다. 
2. 그리고 그 소켓이 TCP ip 계층과 연결 될 수 있도록 바인딩을 해야한다.
3. 바인딩이 되면 listen을 해야한다. 클라이언트에서 요청을한다. 그러면 그 요청을 받아야하는데 listen을 하고 있어야 받을 수있다.
4. 만약 요청이오면 나는 accept로 준비를 한다.
5. recv를 통해 데이터를 받는다.
6. send를 통해 데이터를 보내줌
7. 더이상 필요 없음 close

클라이언트
1. 요청을 하려면 소켓이 필요하다
2. 연결을 요청해야한다. 이 커넥트 요청은 listen이 확인하고 던져서 accept가 받게된다.
3. accept되었다는 사실을 알려주고 연결이 된다. send도 되지만 write도 됨 이것을 통해 데이터를 보내줌 
4. recv를 통해 데이터를 받는다.
5. 더이상 요청이 없으면 close

소켓에선 open이 소켓이 하고있다.
만약에 중간에 네트워크 장애가 발생할 수 있다. 이 문제가 발생한 것을 양쪽이 알고있어야한다.

 

-프로세스간 원격 통신과정에서의 예외상황

1. 프로세스 종료

P, Q 프로세스가 있다. P가 데이터를 보낸다 Q는 그것을 받는다. 그러면 Q가 다음 동작으로 결과를 보내야 하는데 결과를 안보내주고 종료되었다.
정상적인 종료, 비정상적 종료 다 일어날 수 있다. P는 이를 알 수 없고 계속 기다린다. 
조치 1) timer가 필요하다, 메시지를 보내고 기다리는 시간을 정해 놓는다. 만약 정한 시간에 오면 성공, 시간이 지났는데도 안오면 time out되어 wait 상태가 중단되고 네트워크 장애가 났다는 메시지를 Q에게 전송한다.

 

P, Q가 있고 P가 메시지를 보낸다. 근데 P가 메시지를 보내자마자 Q가 종료, 그러면 받을 Q가 사라짐. P는 그 사실을 모르고 계속 기다린다.

 

2. 메시지 상실

P, Q 2개가 있다. 마찬가지로 P는 메시지를 write, send 했다. 근데 중간에 에러가 많아서 메시지는 통신 불가능하다 판단하고 버려진다. 그러면 Q는 받질 못한다. 그러면 P는 응답을 받을 수도 없고 Q도 요청 메시지를 받을 수없다.


P가 보내고 Q가 받는것 까진 성공 근데 Q의 응답 메시지가 가다가 중단될 수 있다.

 
해결방법) P가 계속 기다리다 타임아웃되고 P가 Q에게 재전송을 한다. 

 

3. 훼손메시지

P가 메시지를 보내는데 불행하게도 중간에 에러가 났다. Q 입장에서 메시지를 받긴했는데 깨졌다.
해결방법) 재전송으로 해결가능, Q가 깨졌다는 응답을 보낸다. 보내면서 깨져서 모르니까 다시 보내달라고 재전송 요청을 한다.

 

-사례

윈도우는 LPC(Local Procedure Call), RPC(Remote Procedure Call)가 있다.
위 그림은 LPC, main 함수가 있고 그 안에 sub함수가 있다. 
그러면 메인함수 안에서 서버함수를 호출하면 외부에서 호출되어진다. 그리고 다시 리턴되는 원리이다.
이것을 메인함수의 서브함수 p1, 서브 함수 원본이 p2 이면 LPC이다.

만약이 p2가 완전 다른 컴퓨터에 있다. 그리고 중간에 네트워크를 통해 연결되어 있으면 RPC이다.

 

윈도우에서는 소켓의 개념을 파일이 아닌 handle의 개념으로 본다. 클라이언트가 서버에게 connection request 연결을 요청하면 윈도우에선 handle이 만들어진다.(리눅스에선 소켓)
handle이 만들어진 다음 부터는 handle로 서로 wirte, read를 한다. 
가운데에서 인터넷, 네트워크를 통해 주거니 받거니한다. handle을 통해 받은 데이터를 주거니 받거니 한다.

 

소켓은 인터넷, 네트워크 따라서 서로의 ip 주소를 알아야 커뮤니케이션이 된다. 소켓 주소와 port 주소, ip 주소를 서로 연결시켜줘야하고 연결하는 것이 bind이다.

 

  • 사례연구

-병행프로세스(Linux, C) - (Multi-process 프로그래밍)

프로세스들이 실제적으로 어떻게 사용되는지
멀티프로세스 프로그래밍, 생산자-소비자 구조

process_code가 fork로 자식 프로세스를 만들고 부모는 consumer역할 자식 프로세스는 데이터를 만드는 producer을 한다.
fork는 부모의 pcb를 복사해서 자식의 pcb만들고, 부모 프로세스 이미지 복사해서 자식 프로세스 이미지 만들기한다.
복사해서 2개를 따로 사용한다, 즉 공유 자원을 따로 사용 

 

코드

데이터를 넣으면 consumer는 대기한다. 왜냐면 producer는 자기의 버퍼에다가 집어 넣는다. consumer는 자기의 버퍼에서 꺼내 올려고한다. 프로듀서는 6개까지 다 풀로 집어 넣으면 컨슈머가 뽑아 가길 기다린다. 컨슈머는 버퍼에서 뽑아와야하는데 비어있다. 그래서 대기를한다. 두 개의 buffer 공간은 별도 공간이라 그렇다.

buffer, in, out는 전역변수

 

main

main에서는 fork로 만들고 리턴을 2번한다. 0, 양수
0으로 리턴되면 부모 프로세스
양수로 리턴이면 부모 프로세스
child에게는 프로듀서라는 함수를 호출
parent에게는 컨슈머라는 함수 호출

 

producer

프로듀서, 데이터 만듬
랜덤하게 데이터 생성, 19로 나누고 그러면 0~18중 값이 나온다 그래서 +1을 해준다.
혹시 스택이 다 차있는지 체크한다. 프로듀서 wait을 출력하고, 1초를 재운다음에 1초 후 깨어나서 꽉찼는지 계속 체크
sleep을 사용하는 이유는 대기 모드로 변환을 시켜주기 위해서이다. cpu가 저 조건을 계속 체크하면 비효율적이다. 그래서 1초에 수십만번 체크하는거 보단 1초 후에 다시 체크하는게 굉장히 효율적이다.
만들어진 데이터를 버퍼에다 집어 넣는다.
in 증가 시킨다
1초재운다. 결국 1초마다 데이터를 넣게되는 것이다.

 

consumer

버퍼에서 데이터 1개를 꺼내온다
버퍼가 비어있는지 체크
비어있으면 컨슈머 wait하고 1초를 재운다.
데이터를 가져오고
데이터를 화면에 찍어준다.
out 포인트 재조정
꺼내온 데이터 다시 출력
1초를 재운다.

 


컨슈퍼, 프로듀서는 서로 다른 버퍼를 가지고 동작해서 계속 wait만 하고 수행을 하지 못한다.

 

-병행프로세스 (Linux, C) - (Multi-threads 프로그래밍)

사진 오타-> tread_code

하나의 프로세스 안에 스레드 2개를 만들고 프로듀서, 컨슈머를 만듬 
스레드라 전역변수를 공유한다. buffer, in, out 공유

 

코드

공유 자원인 전역 변수 buffer, in, out이 있다.

 

-메인

스레드를 2개 생성하고 각각 프로듀서, 컨슈머로 역할을 준다.
pthread_join 이건 두개가 동시에 돌다가 동기를 맞추는 경우에 join을 썼다. 만약 스레드1이나 스레드2중 하나가 먼저 끝나거나 안끝나면 join 프로그램이 일 시킨 2개의 일이 완전 끝나야지만 종료하도록 만들고싶다. 그러면 join 2가지를 걸어서 두가지 모두 끝나고 return 0;가 되도록한다.

1번 스레드 프로듀서, 2번 스레드 컨슈머 버퍼를 공유해서 각자 돌아간다.
프로듀서는 in, 컨슈머는 out을 사용, 공유자원은 buffer

 

-producer


프로듀서는 랜덤값 만들어서 버퍼에 저장한다. 다만 꽉 찼는지 체크하고 집어 넣는다. 꽉 찼으면 wait, sleep를 써도 상관 없다.

 

-consumer

데이터를 빼가는데 비어있는지 체크하고 비어있음 기다린다. 비어있지 않으면 데이터 빼고 출력하고 out 재조정한다.

 

프로듀서 컨슈머 일부러 시간차를 두었다. sleep(3), sleep(9)
컨슈머 입장에선 느리게 빼가니까 버퍼 안에 데이터가 더 많이 쌓여있다. 시간차가 있어서 동작이된다.

 


=>결국 병행프로세스는 프로세스는 안되고 스레드만 가능하다.

 

-IPC(PIPE) (Linux, C) - (PIPE 프로그래밍)

pipe는 2개의 프로세스간에 파이프를 만들어서 데이터를 보내는 것이다. 
프로듀서가 파이프를 이용해서 만든 데이터를 컨슈머에게 보낸다.

 

메인

pipe라는 시스템 콜을 이용해서 파이프를 만든다. 이때 파이프를 지정해주는 변수가 들어갈 수 있다. 오른쪽 그림보면 프로듀서의 역할을 하는 자식은 송신용 파이프로 쓰고자하는것, 컨슈머는 수신용 파이프로 쓰고 싶다. 파이프는 방향성이 있다. 한쪽 방향으로만 간다. 다른쪽으로 보내고 싶으면 파이프를 하나 더 만들어야한다.

송신용 수신용이 필요해서 파이프 아이디를 배열로 만듬

fork로 프로세스를 만든다.
프로듀서한테는 송신용으로 쓰라고 만든다.
컨슈머한테는 수신용 파이프로 쓰라고 만든다.

 

producer

데이터를 만들어서 송신하는 목적
데이터를 랜덤하게 만들고 
데이터를 파이프로 버퍼안의 내용을 보낸다. 버퍼안의 내용은 데이터이다. 문자열로 만들어야해서 변환 한 것 뿐이다.
버퍼안에 있는 내용을 버퍼 사이즈만큼 읽어서 pipe로 wire해라, 보내라는 의미 -> 송신이된다.

 

consumer

수신용 파이프를 받아온다, 이걸로 내용을 받는다.
데이터를 받아야한다. 버퍼에 read해서 저장한다.
수신한 데이터를 화면에 출력

두가지는 2초간격으로 데이터를 보내고 받아라 한것이다.

 


첫번째 프로세스끼리 할 때 안되는데, 이를 대체하기 위한 방법이 pipe 방법이다.

 

-상호배제(Mutex) (Linux, C)

하나의 프로세스가 있고 2개의 스레드로 만들었다.
스레드1은 loop1, 스레드2는 loop2는 각자 돌면서 sharedresource를 증가 시키게 만든다. 2개의 스레드 모두다 sharedreource를 증가 시키게 만들고 싶은 것이다.
공유자원=sharedresource 

 

이런식으로 2개의 스레드가 경쟁적으로 증가시키고있다 => 임계영역에 문제가 발생

 

코드

임계 영역 문제 해결 방법 => 상호배제
세마포어를 이용했다.
mutex는 상호배제, 그래서 세마포어 변수  mutex를 선언

mutex는 헤더파일에 자료형으로 정의되어있다. mutex, 즉 세마포어 변수를 쓰고싶으면 자료형으로 변수를 사용하면되고 초기값을 상수로 선언해야한다. 상수는 헤더 파일에 저장
공유자원 변수 선언

 

메인

공유자원 초기값 설정
스레드 2개 만들기
1번 스레드 do_1oop1 일거리, 2번 스레드 do_loop2 일거리 던져줌

 

2개의 스레드를 돌리고 정상적으로 끝나면 join하고 join이 잘 끝나면 세마포어 변수를 해제시킨다. 이렇게해서 전체적인 프로그램에 문제가 없도록 한다.

 

do_loop1, do_loop2

shardedresoure를 증가 시키는 것이 목적이다. 하지만 임계 영역 문제가 발생, 빨간색 박스가 임계영역이다. 이문제 해결하기 위해 상호배제를 해야한다. 세마포어 사용

mutex라는 변수를 이용해서 락을 걸어줬다.
임계 영역으로 들어가서 실행하고
언락을 시켜줬다. 풀어줘야지만이 두번째 스레드가 임계 영역에 들어갈 수 있다.
따라서 2개가 동시에 들어가지 않는다.

그런데 1번 스레드 코드 임계 영역안에 일부러 if문 추가(오류 예시)(중요)
0부터 5까지 반복되는 상태인데, i가 3이되는 시점에 그냥 리턴을 시켰다. 즉 임계 영역을 unlock하지 않고 리턴하게 했다.

그러면 사진 처럼 된다. 
4번 반복한 시점에서 리턴하게된다. 그래서 1번 스레드는 멈추고 2번 스레드는 1번 스레드가 풀어주지 않아서 진입 영역에서 풀어주기를 기다리고있는다. 더 이상 진행하지 않는다. 

만약에 프로그램을 짜다가 실수로 세마포어를 풀어주지 않고 종료가 되면 다른 스레드는 계속 대기한다는 문제가 발생

728x90
반응형
Comments