일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
31 |
- appcompatacitivity
- 물리 메모리
- DiffUtil
- 데코레이터 패턴
- Android
- AsyncListDiffer
- Kotlin
- 운영체제
- 디자인 패턴
- http 역사
- AAC
- 자이고트
- 절대 주소
- 리사이클러뷰풀
- 안드로이드
- apk 빌드 과정
- NestedScrollView
- appcompatactivity
- 상태관리
- flutter
- 뷰홀더
- 내부 단편화
- 리사이클러뷰
- viewModelScope
- 플로이드워셜
- Dispatchers
- recyclerview
- GetX
- 프로세스
- http발전과정
- Today
- Total
hong's android
[CS] 프로세스 동기화 본문
프로세스 간 통신 (IPC)
프로세스가 다른 프로세스와 데이터를 주고받는 프로세스 간 통신에는 같은 컴퓨터 내에 있는 프로세스뿐만 아니라 네트워크로 연결된 다른 컴퓨터에 있는 프로세스와의 통신도 포함된다.
프로세스는 각각의 가상 메모리를 독립적으로 할당받고, 다른 프로세스의 가상 메모리에 접근할 수 없다. 프로세스 외부에서 메모리를 마음대로 변경할 수 없게 해야 하기 때문이다. 그래서 다른 프로세스와 통신을 하기 위한 방법은 아래의 방법들이 있다.
1) 프로세스 내부 데이터 통신
하나의 프로세스 내에 2개 이상의 스레드가 존재하는 경우
2) 프로세스 간 데이터 통신
같은 컴퓨터에 있는 여러 프로세스끼리 통신하는 경우
책에는 나와있지 않았지만, 프로세스 간 통신을 위해 메모리에 접근하는 방식은 Shared Memory 방식이라고도 한다.
3) 네트워크를 이용한 데이터 통신
여러 컴퓨터가 네트워크로 연결되어 있을 때도 통신이 가능한데, 이 경우 프로세스는 소켓을 이용하여 데이터를 주고받는다.
Shared momory를 사용하는 통신 방식의 가장 큰 문제는 언제 데이터를 보낼지 데이터를 받는 쪽에서는 모른다는 것이다. 그러므로 데이터를 받는 쪽은 반복적으로 shared memory의 값을 확인해야한다. 이를 busy waiting이라고 한다.
공유 자원 (Shared Resource)
여러 프로세스가 공동으로 이용하는 변수, 메모리, 파일 등을 말한다. 프로세스들의 공유 자원 접근 순서를 정하여 예상치 못한 문제가 발생하지 않도록 해야 한다.
임계 구역 (Critical Section)
공유 자원 접근 순서에 따라 실행 결과가 달라지는 프로그램의 영역을 임계 구역이라고 한다. 각 프로세스가 Shared Memory를 사용하는 부분, 즉 데이터를 확인하고 업데이하는 하는 부분이다. 즉, 공유 데이터의 일관성을 보장하기 위해 하나의 프로세스/스레드만 진입해서 실행 가능한 영역이다.
Race condition(경쟁 조건)
여러 프로세스/스레드가 동시에 같은 데이터를 조작할 때 타이밍이나 접근 순서에 따라 결과가 달라질 수 있는 상황
근본적으로 컴퓨터는 저수준 언어로 실행하기 때문에 여러 줄의 저급 언어로 변환된 고급 언어가 한줄한줄 실행되며 race condition 문제가 발생한다. 결국 임계 구역(공유 자원에 대한 동시 접근을 막는 코드 영역)을 통해 Synchronization (동기화)가 필요하다.
1을 가진 하나의 state 값에 두개의 스레드가 접급해서 값을 더하는 경우를 생각해 보자.
싱글 코어인 상황
로직들은 아래와 같은 순서로 cpu에서 실행된다.
1. 메모리에 저장된 state값을 읽어 들인다.
2. 읽어 들인 state값에 1을 더한다.
3. 메모리에 다시 state값을 저장한다.
만약 1번, 2번이 실행된 후 컨텍스트 스위칭이 발생한다면 메모리에 연산된 값이 저장되어있지 않기 때문에 이전 스레드에서 연산이 되기 전 값을 메모리에서 가져와서 연산을 시작할 것이다.
결국 두 개의 스레드가 두 번 연산을 했지만 예상과 다른 결과를 나온다.
멀티 코어인 상황에선 컨텍스트 스위칭이 발생하지 않겠지만, 결국 두 개의 스레드가 병렬적으로 실행되면 똑같은 문제가 발생한다.
생산사 - 소비자 문제
생산자 프로세스와 소비자 프로세스가 서로 독립적으로 작업을 한다. 생산자는 계속 물건을 생산해서 버퍼에 넣고 소비자는 계속 버퍼를 사용한다. 또한 버퍼가 비었는지 가득 찼는지 확인하기 위해 sum이라는 전역 변수를 사용하는데, sum에는 현재 버퍼에 있는 상품의 총수가 저장된다.
하지만, 생산자와 소비자가 전역 변수 sum에 접근하는 타이밍을 서로 맞추지 않으면 문제가 발생한다.
1) 생산자가 물건 하나를 buf 4에 저장했다. sum을 4로 바꿔야 하나 아직 바꾸지 못했다.
2) 소비자가 물건 하나를 소비했다. sum을 2로 바꿔야 하나 아직 바꾸지 못했다.
3) 이 상태에서 생산자의 sum = sum + 1과 소비자의 sum = sum - 1이 거의 동시에 실행되면 문제가 발생한다. 생산자와 소비자가 독립적이기 때문에 상대방이 sum을 바꾸려고 하는 것을 모른 채 현재 상태인 sum = 3을 읽어서 작업을 한다.
임계구역을 통해 해당 문제를 해결하기 위해선 아래와 같은 조건들이 필요하다.
- 상호 배제
한 프로세스가 임계구역에 들어가면 다른 프로세스는 임계구역에 들어갈 수 없다.
- 한정 대기
한 요리사가 믹서를 계속 사용하여 다른 요리사가 믹서를 사용하지 못한 채 계속 기다리면 안 되는 것처럼 어떤 프로세스도 무한 대기하지 않아야 한다.
- 진행의 융통성
한 프로세스가 다른 프로세스의 진행을 방해해서는 안된다.
임계구역 해결 방법
상호 배제 문제
두 프로세스가 공유하는 변수인 lock을 통해 임계구역의 잠금을 설정하는 방법이 있다고 하자. 만약 lock == true 이면 임계구역에서 작업하고 있다는 뜻이므로 잠금이 해제될 때까지 무한 루프를 돌면서 기다린다. 락을 가질 수 있을 때까지 반복해서 시도하기 때문에 기다리는 동안 cpu를 낭비한다는 단점이 있다.
while(lock==true);
lock = true;
// 임계 영역
lock = false;
프로세스 p1, p2 모두 위 코드와 동일하다고 했을 때, while(lock == true) 조건문을 통과하고 타임아웃이 발생할 경우 두 개의 프로세스가 임계영역에 들어갈 수 있는 문제도 생긴다.
한정 대기 문제
한정 대기 문제가 언제 발생하는지 살펴보자.
// 프로세스 p1
lock = true;
while(lock2==true);
// 임계 구역
lock1=false;
// 프로세스 p2
lock2=true;
while(lock1=true);
// 임계 구역
lock2=false;
위 예시는 두개의 lock을 사용해서 상호 배제를 보장한다. 하지만 프로세스 p1이 lock=true;문을 실행한 후 콘텍스트 스위칭을 한경우엔 두 프로세스 모두 무한 대기 현상이 일어난다. 또한 프로세스가 늘어나면 검사해야 하는 lock의 개수가 늘어나 비효율적이다.
진행의 융통성 문제
lock 값이 1이면 프로세스 P1이 임계구역을 사용한다는 뜻이고, lock 값이 2이면 프로세스 P2임계구역을 설정한다고 하자.
// 프로세스 p1
while(lock == 2);
// 임계 영역
lock = 2;
// 프로세스 p2
while(lock == 1);
// 임계 영역
lock = 1;
상호 배제와 한정 대기를 보장한다. 하지만 서로 번갈아 실행되면서 프로세스 p1은 프로세스 p2가 임계구역에 진입했다가 나온 다음에야 다시 진입할 수 있으므로 프로세스 p2가 프로세스 p1의 진행을 방해하는 구조이다.
* 하드웨어적인 해결 방법
앞서 살펴보았듯이 잠금이 걸렸는지 검사하는 while(lock == true) 문과 검사한 후 잠금 설정을 하는 lock = true 문이 분리되어 실행되면(즉 두 명령어 중간에 타임아웃이 걸리면) 문제가 발생한다. 이 경우 하드웨어적으로 두 명령어를 동시에 실행하면 임계구역 문제를 쉽게 해결할 수 있다.
피터슨 알고리즘
turn이라는 공유 변수와 lock1, lock2 변수를 사용하여 임계 구역을 설정하는 방식
세마포어
앞서 살펴본 임계구역 해결 알고리즘은 바쁜데기를 사용하거나 사용하는 방법이 복잡하다. 이러한 단점을 해결하기 위해 세마포어 알고리즘이 등장하게 되었다.
세마포어는 임계구역에 진입하기 전에 공유 가능한 자원의 수 n을 감소시킨다. 임계구역에서 프로세스가 작업을 마치면 세마포어는 다음 프로세스에 임계구역이 잠겼는지 직접 점검하거나, 바쁜 대기를 할 필요가 없이 다음 프로세스에 임계구역을 사용하라는 동기화 신호를 보낸다.
Semaphore(n);
P(); // 잠금을 수행하는 코드, n이 0보다 크면 1을 감소 시키고 임계구역에 진입, 작으면 0보다 커질때까지 기다린다.
// 임계 구역
V(); // 잠금 해제와 동기화를 같이 수행하는 코드
세마포어의 P()나 V() 내부 코드가 실행되는 도중에 다른 코드가 실행되면 상호 배제와 한정 대기 조건을 보장하지 못한다. 그러므로 P()와 V()의 내부 코드는 검사와 지정을 사용하여 분리 실행되지 않고 완전히 실행되게 해야 한다.
모니터
모니터는 Monitor = mutex + one or more condition variables라고 정의할 수 있다.
세마포어는 wait, signal 함수를 명시하는 것이 번거롭고, 더군다나 자칫 잘못된 코드로 예기치 못한 결과를 얻을 수도 있다.
그렇기 때문에 공유 자원과 공유 자원에 접근하기 위한 인터페이스를 묶어 관리하는 모니터가 등장하게 되었다. 모니터는 공유 자원을 내부적으로 숨기고 공유자원에 접근하기 위한 인터페이스만 제공함으로써 자원을 보호하고 프로세스 간에 동기화를 시킨다.
이를 위해 모니터를 통해 공유 자원에 접근하고자 하는 프로세스를 큐에 삽입하고, 큐에 삽입된 순서대로 하나씩 공유 자원을 이용하도록 한다.
이 밖에도 모니터는 세마포어와 마찬가지로 실행 순서 제어를 위한 동기화도 제공한다. 특정 조건을 바탕으로 프로세스를 실행하고 일시 중단하기 위해 모니터는 조건 변수를 사용하는데 조건 변수는 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 변수이다.
조건 변수로는 wait와 signal 함수를 이용할 수 있다. wait은 호출한 프로세스의 상태를 대기 상태로 전환하고 일시적으로 조건 변수에 대한 대기 큐에 삽입하는 연산이다. signal은 wait를 호출하여 큐에 삽입된 프로세스의 실행을 재개하는 연산이다.
출처
혼자 공부하는 컴퓨터 구조 + 운영체제
'Develop > Cs' 카테고리의 다른 글
[CS] 물리 메모리 관리 (0) | 2025.02.19 |
---|---|
[CS] 프로세스와 스레드 (1) | 2025.01.17 |
[cs] HTTP의 발전 과정 (0) | 2024.10.28 |
[Cs] 컨텍스트 스위칭 (0) | 2023.01.13 |