일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 운영체제
- concurrency
- Class
- 43. Multiply Strings
- Protocol
- LeetCode
- Decorator
- 315. Count of Smaller Numbers After Self
- Regular Expression
- 밴픽
- 30. Substring with Concatenation of All Words
- data science
- 컴퓨터의 구조
- attribute
- kaggle
- t1
- 파이썬
- 715. Range Module
- 프로그래머스
- Python Implementation
- Convert Sorted List to Binary Search Tree
- Generator
- shiba
- iterator
- 시바견
- Python Code
- DWG
- 109. Convert Sorted List to Binary Search Tree
- Substring with Concatenation of All Words
- Python
- Today
- Total
Scribbling
운영체제 - 5 본문
1. 프로세스 간 통신
1.1 프로세스 간 통신의 개념
독립적인 프로세스끼리 서로 데이터를 주고 받는 경우 통신을 사용한다. 프로세스끼리 통신을 하는 경우 누가 먼저 작업할지, 작업이 언제 끝날지 등을 서로 알려주어야 하는데 이를 동기화라고 한다.
- 프로세스 내부 데이터 통신: 하나의 프로세스 내의 2개 이상의 스레드가 통신하는 방식.
- 프로세스 간 데이터 통신: 여러 프로세스끼리 통신하는 경우.
- 네트워크를 이용한 데이터 통신: 여러 컴퓨터가 네트워크로 연결되어 있을 때 프로세스의 소켓을 이용한 통신 방식.
1.2 바쁜 대기와 동기화
전역 변수를 사용하여 통신하는 경우의 가장 큰 문제는 언제 데이터를 보낼지 데이터를 받는 쪽에서 모른다는 것이다. 데이터를 받는 측에서는 반복적으로 전역 변수의 값을 체크해야만 하는데, 이러한 상태를 바쁜 대기(busy waiting)이라고 한다. 이는 시스템 차원에서 매우 큰 자원 낭비이다. 바쁜 대기 문제를 해결하려면 데이터가 도착했음을 프로세스에게 알려주면 되는데, 이를 동기화(synchronization)이라고 한다.
1.3 프로세스 간 통신의 종류
프로세스 간 통신은 데이터를 주거나 받는 동작이며 이는 쓰기 연산과 읽기 연산으로 간소화할 수 있다. 프로세스 간 통신에서 핵심은 프로세스 동기화이다.
A. 전역 변수를 이용한 통신
- 주로 부모와 자식 프로세스가 통신하는 방식이다. 동기화 문제가 있어서 바쁜 대기가 필요하며, 단방향 통신이다.
B. 파일을 이용한 통신
- 파일 기술자(file descriptor)를 이용한다. 역시 부모-자식 관계 프로세스 간 통신에 많이 사용되며 동기화가 필요하다. 주로 부모 프로세스가 wait()함수를 이용하는 방식으로 동기화한다.
C. 파이프를 이용한 통신
- 파이프는 운영체제가 제공하는 통신 방식이며 단방향 통신이다.
D. 소켓을 이용한 통신
- 여러 컴퓨터에 있는 프로세스 간 통신을 네트워킹이라고 한다. 네트워킹 상황에서의 통신은 원격 프로시저 호출이나 소켓을 이용한다. 원격 프로세스 호출은 다른 컴퓨터에 있는 함수를 호출하는 것이다. 일반적으로 원격 프로세스 호출은 소켓을 이용하여 구현한다. 소켓은 프로세스 동기화를 지원하므로 바쁜 대기를 하지 않아도 된다. 소켓은 양방향 통신이다.
2. 공유 자원과 임계구역
2.1 공유 자원의 접근
공유 자원(shared resource)은 여러 프로세스가 공동으로 사용하는 변수, 메모리, 파일 등을 의미한다. 공유 자원은 공동으로 이용되므로 누가 언제 데이터를 읽고 쓰냐에 따라 결과가 달라질 수 있다. 2개 이상의 프로세스가 공유 자원을 병행적으로 읽거나 쓰는 상황을 '경쟁 조건(race condition)이 발생했다'고 한다.
2.2 임계구역
공유 자원 접근 순서에 따라 실행 결과가 달라지는 프로그램 영역을 임계구역(critical section)이라고 한다. 임계구역에서는 프로세스들이 동시에 작업하면 안된다. 어떤 프로세스가 임계구역에 들어가면 다른 프로세스는 임계구역 밖에서 기다려야 하며 임계구역의 프로세스가 나와야 들어갈 수 있다.
임계구역은 하드웨어 자원을 사용할 때도 적용되는 개념이다. 예컨대 1대의 프린터를 여러 사람이 사용하는 경우가 이에 해당된다. 이러한 문제를 피하기 위해 하드웨어 자원도 한 번에 한 프로세스만 사용 가능하다.
2.3 임계구역의 해결 조건
- 상호 배제 (Mutual Exclusion)
- 한정 대기 (Bounded Waiting)
- 진행의 융통성 (Progress Flexibility)
3. 임계구역 해결 방법
임계 구역 문제는 잠금(lock)을 이용하여 해결 가능하다.
3.1 세마포어
세마포어 (Semaphore)는 임계구역에 진입하기 전에 스위치를 사용 중으로 놓고 임계구역으로 들어간다. 이후에 도착하는 프로세스는 앞의 프로세스가 작업을 마칠 때까지 기다린다. 프로세스가 작업을 마치면 세마포어는 다음 프로세스에 임계구역을 사용하라는 동기화 신호를 보낸다. 세마포어는 바쁜 대기가 필요없으며, 프로세스가 직접 다른 프로세스에 동기화 메시지를 보낼 필요가 없다.
- Semaphore(n): RS (현재 사용 가능한 자원의 수) = n
- P(): 잠금을 수행하는 코드로, RS가 0보다 크면 1만큼 감소시키고 임계 구역에 진입한다. 만약 RS가 0보다 작거나 같으면 0보다 커질 때까지 기다린다.
- V(): 잠금 해제와 동기화를 같이 수행하는 코드로, RS 값을 1 증가시키고 세마포어 큐에 있는 프로세스에게 wake_up 신호를 보낸다.
* P()와 V() 내부 코드는 '검사와 지정'을 사용하여 분리 실행되지 않고 완전히 실행되게 해야 한다. 여기서 '검사와 지정'은 하드웨어적 도움을 받아서 명령어가 진행되는 도중에 인터럽트 되지 않도록 하는 것을 일컫는다.
3.2 모니터
모니터는 공유 자원을 내부적으로 숨기고 공유 자원에 접근하기 위한 인터페이스만 제공함으로써 자원을 보호하고 프로세스 간에 동기화를 시킨다. 임계구역으로 지정된 변수나 자원으로 접근하고자 하는 프로세스는 직접 P() 혹은 V()를 사용하지 않고 모니터에 작업 요청을 한다. 모니터는 요청받은 작업을 큐에 저장하여 순서대로 처리하고, 그 결과를 해당 프로세스에 전달한다. 이 방법은 사용자 측면에서는 복잡한 코드가 불필요하다는 점이 장점이며, 시스템 입장에서는 임계구역을 보호할 수 있다는 것이 장점이다.
4. 통신 프로그래밍
4.1 파일을 이용한 통신
앞서 언급한 바와 같이, 파일을 이용한 통신은 동기화가 필요하다. 부모-자식 프로세스간의 동기화는 부모 프로세스에 wait()를 사용하여 가능하다. 참고로 fork() 이전에 파일을 open()하면 생성된 파일 기술자가 자식 프로세스에도 상속된다. fork()는 부모 프로세스의 자원 대부분을 상속시키는데, 이에 당연히 파일 기술자도 포함된다. 다만, 부모 및 자식 프로세스가 읽거나 쓰면 파일 기술자는 전진한다는 점을 주의해야 한다. 예컨대 자식 프로세스에서 파일 기술자로 'Hello\n"를 썼다면, 부모 프로세스는 파일 기술자의 위치를 원점으로 옮긴 다음에 해당 데이터 ('Hello\n')를 읽을 수 있다.
4.2 네트워킹
아래 그림은 클라이언트와 서버가 통신하는 방식을 보여준다. 클라이언트 및 서버 모두 소켓을 사용한다. 소켓은 양방향 통신 및 동기화를 지원한다.
클라이언트는 소켓을 생성한 후 connect()를 사용하여 서버와의 접속을 시도한다. 서버와 접속되면 소켓 기술자가 생성되어 read() 혹은 write() 작업을 하며, 작업이 끝나면 소켓 기술자(socket descriptor)를 닫고 종료한다.
서버는 소켓을 생성한 후 bind()를 사용하여 생성한 소켓을 특정 포트에 등록한다. 네트워크 환경에서는 각 컴퓨터가 IP 주소로 구분된다. 컴퓨터 내에는 여러 프로세스가 존재하기 때문에 어떤 프로세스와 통신할지 구분해야 하는데, 이때 사용하는 구분 번호를 포트 번호(port number)라고 한다. 하나의 포트에는 여러 소켓이 생성된다. 이는 당연한 것으로, 하나의 서버가 여러개의 클라이언트와 통신하기 때문이다.
bind()로 소켓이 특정 포트에 정상적으로 등록되면 listen()을 실행하여 클라이언트는 받을 준비를 한다. accept()는 클라이언트의 connect(), 연결 요청을 기다리다가 여러 개의 클라이언트가 동시에 connect()를 하는 경우 그중 하나를 골라 작업한다. 여기서 클라이언트가 accept()하면 소켓 기술자가 생성되고 작업이 시작된다. read() 혹은 write() 작업을 마치면 소켓 기술자를 닫고 다음 클라이언트를 기다린다.
* 루프백 주소: 인터넷이 연결되어 있지 않아도 사용 가능한 IP 주소로, 127.0.0.1로 정해져 있다.
'Computer Science > Computer Knowledge' 카테고리의 다른 글
운영체제 - 7 (0) | 2021.10.16 |
---|---|
운영체제 - 6 (0) | 2021.10.11 |
운영체제 - 4 (0) | 2021.10.05 |
운영체제 - 3 (0) | 2021.10.03 |
운영체제 - 2 (0) | 2021.09.27 |