- ProcessA와 B가 동시에 공유 메모리를 access(접근)하기 원하는 상태. 경쟁상황이 발생할 수 있고, 경쟁 결과에 따라 결과값이 변경될 수 있다.
Critical Regions
race condition을 피하기 위한 필요 조건
Mutual Exclusion : 상호배제, 동시에 임계구역에 들어갈 수 없도록한다.
Progress : 임계 영역 밖에서 실행되는 어떠한 프로세스도 다른 프로세스를 차단할 수 없다.
Bounded Waiting : 임계 영역에 들어가기 위해 영원히 기다리는 프로세스는 없도록 한다.
상호배제(Mutual Exclusion)를 구현하기 위한 제안
Disabling interrupts
Lock variables
Strict alternation
peterson's solution
The TSL instruction
Strict Alternation
process j가 임계 영역에 들어갈때까지 process i는 계속 대기 상태가 되어 실행되지 않는다. 제대로된 해결책이 아님!
Dekker's Solution
Process i는 상대방 flag를 보고 j가 TRUE면 while문에서 기다린다. FALSE이면 turn이 j인지 확인하고, j라면 자신의 flag를 FALSE로 만들고 turn이 i가 될때까지 기다린다. turn이 i이면 그때 임계구역에 들어갈 수 있다.
- flag: 들어가겠다는 표지
- turn: 실제 배정받은 turn(실행중 표시)
Peterson's Solution
Dekker와 비슷하지만 여기서 turn의 의미는 양보할 프로세스이다. Process i는 flag가 i, turn이 j일때까지 기다렸다가 임계구역에 들어간다.
Bakery Algorithm
프로세스(쓰레드)의 개수가 n개일때, 빵집처럼 번호표를 받아서 번호표가 같을 때 고유 id 순으로 임계 영역에 들어간다.
The TSL Instruction
위 빵집알고리즘은 소프트웨어적 도구인데, 이를 수행하기에는 너무 heavy함으로 하드웨어의 도움이 필요하다. 이에 TSL Register를 도입하여 하드웨어적으로 작성한다. (TSL = Test and Set Lock)
TSL은 Lock 변수를 register로 가져와서 1로 세팅한다. 세팅 이전의 Lock값이 0인지 확인 한 후, 0이라면 return하여 임계구역에 진입하고 1이라면 다른 process가 이미 1로 세팅하여 사용중이므로 loop를 돌며 확인한다.
XCHG는 Lock변수와 Register를 exchange(swap)하여 TSL과 같은 과정을 거친다.
The Producer-Consumer Problem
Producer-Consumer관계의 두 프로세스는 둘 다 Sleep할 수 있는 치명적인 race condition을 가질 수 있다.
producer는 item을 만들어서 queue에 넣고, count가 N에 도달(queue가 꽉 참)하면 스스로 sleep한다. 이를 consumer가 count가 N-1이 될 때(꽉 차지 않게됨)를 확인 후 producer를 깨워주는 방식으로 동작한다.
producer의 sleep직전에 cousumer가 실행되어 wakeup하게되면 producer는 sleep상태를 유지하게되고 이후 cousumer는 큐를 모두 소비하고 sleep하게되므로 결국 둘 다 sleep하게되는 문제가 발생한다. 이는 반대의 경우(consumer의 sleep직전에 producer가 실행되어 wakeup)도 마찬가지로 문제가 발생한다.
Semaphores
Semaphore는 Up&Down연산자를 사용하고, mutual exclusion(상호배제)와 synchronization(동기화)를 위해 사용될 수 있다.
down(mutex)를 producer와 consumer가 동시에 호출해도 OS자체에서 한 프로세스만 down하도록 한다.
만약 producer가 down mutex를 하면 1에서 0으로 바꾸어 먼저 수행하고, consumer는 0에서 -1로 바꾸어 실행을 대기한다(sleep).
이후 producer가 작업을 수행하고 임계 영역을 나올 때 mutex를 up하면 -1에서 0로 바뀌고 sleep을 호출한 프로세스(consumer)를 깨워주고 consumer은 바로 semaphore을 획득하여 임계 영역에 들어가 바로 실행하게 된다.
Priority Inversion(우선순위 역전)
sleep과 wakeup이 수행될 때 우선순위를 기반으로한 선점 스케줄링(priority-based preemptive scheduling scheme)에서 우선순위 역전이 일어날 수 있다.
T3이 필요한 데이터를 Lock을 하여 실행중인데, T1이 깨어나서 수행 시 T3이 Lock을 한 데이터를 필요로 한다. 이 때 T1은 T3이 수행 종료되어 Lock을 반환할 때 까지 기다려야하는데, 그 사이 T2가 스케줄링되어 실행되면 T2가 T1보다 먼저 수행되며 종료하는 우선순위 역전이 생길 수 있다.
Priority Inheritance
T1의 우선순위를 T3에게 상속하여 T3 수행 중에 T2는 깨어나도 T3이 우선순위가 더 높기 때문에 T3이 수행 종료된 후 수행된다.
Mutexes
Semaphore는 OS에 시스템 호출을 함으로써 상호배제를 구현한다. 반대로 Mutex는 OS에 부탁하지 않고 독립적으로 상호배제를 할 수 있는 방법이다.
Mutex는 쓰레드들 간에 OS 공유없이 가능한 공유방법으로, 하나의 프로세스 내에서 TSL연산을 그대로 이용할 수 있다.
따라서 Mutex는 멀티 쓰레드로 구현하고 싶을 때 효율적일 수 있다.
Mutexes in pthreads
대부분의 OS는 Mutex연산을 제공하여 하나의 프로세스 안에서 멀티 쓰레드로 일을 할 때 사용하는것이 가능하다!
하지만 mutex는 semaphore과는 다르게 동기화(sleep-wakeup)는 해주지 못하기 때문에 condition 변수를 도입하였다.
이때 만약 producer가 lock을 하고 버퍼가 MAX에 도달하면 unlock하지 않고 잠들게되어 consumer는 이를 깨워줄 수 없게 된다. 따라서 sleep직전에 unlock하도록 설계되어있고, 깨어날 때 lock을 하지 않고 깨면 안되므로 lock을 하고 깨어나도록 하는 코드도 설계되어 있다.
Monitors
up&down연산(high level)과 lock&unlock연산(low level)은 설계시 코드가 수천줄이 넘어가면 up&down쌍을 맞추기 어렵다는 문제점이 있다.
Monitor은 동기화를 프로그래머가 설계하는것이 아니라 컴파일러 수준에서 하도록 설계한 것이다.
2개의 쓰레드가 동시에 실행되는 중에 동시에 insert, remove를 부르게 되더라도 컴파일러가 알아서 동시에 실행되지않도록 구현된다.
Structure of a Monitor
프로세스들은 Queue에서 기다리다 하나씩모니터로 들어와 실행한다.
첫번째 프로세스가 실행하다 sleep하는 코드를 만나면 monitor의 waiting area로 들어가서 기다린다.
그동안 모니터가 비게되면 두번째 프로세스가 들어와서 실행한다.
이때 첫번째 프로세스를 wake up해주는 코드가 있다고 하면 깨워준 이후 두 프로세스는 동시에 수행될수 없으므로
두번째 프로세스는 1) wake up을 시켜주고 바로 urgent Queue로 들어가 기다리고 첫번째 프로세스를 실행하거나 / 2) wake up을 시켜주고 쭉 수행 후 종료된 다음 첫번째 프로세스를 실행할 수 있다.
Hoare's Monitor : 1) 방법. 안멈추고 실행시 이후 코드에 따라 다른 일을 하게되면 조건이 훼손될 수 있다는 이유가 명확하다.
Lampson&Redell's Monitor: 2) 방법. 첫번째 프로세스가 깨어나면 바로 실행(if문으로 작성)하는것이 아니라 처음 코드로 다시 돌아가서(while문으로 작성) count가 0인지 확인하는 등의 작업을 하여 조건 훼손 가능성(에러 가능성)이 없도록 구현하였다.
Lock-free Data Structure
CPU의 core수가 많아져서 공유 변수를 수정할 때 Lock이 병목현상을 일으킬 수 있게되어 성능이 떨어질 수 있다.
따라서 CPU는 Atomic한 CAS기능(Compare-and-Swap 명령어)을 제공한다.
OS - 02. Processes and Threads (1)
Race Conditions
- ProcessA와 B가 동시에 공유 메모리를 access(접근)하기 원하는 상태. 경쟁상황이 발생할 수 있고, 경쟁 결과에 따라 결과값이 변경될 수 있다.
Critical Regions
race condition을 피하기 위한 필요 조건
상호배제(Mutual Exclusion)를 구현하기 위한 제안
Strict Alternation
process j가 임계 영역에 들어갈때까지 process i는 계속 대기 상태가 되어 실행되지 않는다. 제대로된 해결책이 아님!
Dekker's Solution
Process i는 상대방 flag를 보고 j가 TRUE면 while문에서 기다린다. FALSE이면 turn이 j인지 확인하고, j라면 자신의 flag를 FALSE로 만들고 turn이 i가 될때까지 기다린다. turn이 i이면 그때 임계구역에 들어갈 수 있다.
- flag: 들어가겠다는 표지
- turn: 실제 배정받은 turn(실행중 표시)
Peterson's Solution
Dekker와 비슷하지만 여기서 turn의 의미는 양보할 프로세스이다. Process i는 flag가 i, turn이 j일때까지 기다렸다가 임계구역에 들어간다.
Bakery Algorithm
프로세스(쓰레드)의 개수가 n개일때, 빵집처럼 번호표를 받아서 번호표가 같을 때 고유 id 순으로 임계 영역에 들어간다.
The TSL Instruction
위 빵집알고리즘은 소프트웨어적 도구인데, 이를 수행하기에는 너무 heavy함으로 하드웨어의 도움이 필요하다. 이에 TSL Register를 도입하여 하드웨어적으로 작성한다. (TSL = Test and Set Lock)
TSL은 Lock 변수를 register로 가져와서 1로 세팅한다. 세팅 이전의 Lock값이 0인지 확인 한 후, 0이라면 return하여 임계구역에 진입하고 1이라면 다른 process가 이미 1로 세팅하여 사용중이므로 loop를 돌며 확인한다.
XCHG는 Lock변수와 Register를 exchange(swap)하여 TSL과 같은 과정을 거친다.
The Producer-Consumer Problem
Semaphores
Semaphore는 Up&Down연산자를 사용하고, mutual exclusion(상호배제)와 synchronization(동기화)를 위해 사용될 수 있다.
down은 count를 감소시키고 만약 카운트가 0보다 작다면 (즉, sleep조건이면) down을 호출한 프로세스를 sleep시킨다.
up도 down과 마찬가지로 count를 증가시키고 만약 카운트가 0보다 같거나 작다면 sleep중인 프로세스를 wake up시켜준다.
각 down과 up과정은 수행중 끼어들 수 없고, 이를 아토믹하게(원자적으로) 진행한다고 한다.
Producer과 Consumer사이에는 유한한 큐 버퍼가 존재하고, Semaphore n, mutex, e를 설정한다.
down(mutex)를 producer와 consumer가 동시에 호출해도 OS자체에서 한 프로세스만 down하도록 한다.
만약 producer가 down mutex를 하면 1에서 0으로 바꾸어 먼저 수행하고, consumer는 0에서 -1로 바꾸어 실행을 대기한다(sleep).
이후 producer가 작업을 수행하고 임계 영역을 나올 때 mutex를 up하면 -1에서 0로 바뀌고 sleep을 호출한 프로세스(consumer)를 깨워주고 consumer은 바로 semaphore을 획득하여 임계 영역에 들어가 바로 실행하게 된다.
Priority Inversion(우선순위 역전)
sleep과 wakeup이 수행될 때 우선순위를 기반으로한 선점 스케줄링(priority-based preemptive scheduling scheme)에서 우선순위 역전이 일어날 수 있다.
T3이 필요한 데이터를 Lock을 하여 실행중인데, T1이 깨어나서 수행 시 T3이 Lock을 한 데이터를 필요로 한다. 이 때 T1은 T3이 수행 종료되어 Lock을 반환할 때 까지 기다려야하는데, 그 사이 T2가 스케줄링되어 실행되면 T2가 T1보다 먼저 수행되며 종료하는 우선순위 역전이 생길 수 있다.
Priority Inheritance
T1의 우선순위를 T3에게 상속하여 T3 수행 중에 T2는 깨어나도 T3이 우선순위가 더 높기 때문에 T3이 수행 종료된 후 수행된다.
Mutexes
Mutexes in pthreads
이때 만약 producer가 lock을 하고 버퍼가 MAX에 도달하면 unlock하지 않고 잠들게되어 consumer는 이를 깨워줄 수 없게 된다. 따라서 sleep직전에 unlock하도록 설계되어있고, 깨어날 때 lock을 하지 않고 깨면 안되므로 lock을 하고 깨어나도록 하는 코드도 설계되어 있다.
Monitors
2개의 쓰레드가 동시에 실행되는 중에 동시에 insert, remove를 부르게 되더라도 컴파일러가 알아서 동시에 실행되지않도록 구현된다.
Structure of a Monitor
Lock-free Data Structure
CPU의 core수가 많아져서 공유 변수를 수정할 때 Lock이 병목현상을 일으킬 수 있게되어 성능이 떨어질 수 있다.
따라서 CPU는 Atomic한 CAS기능(Compare-and-Swap 명령어)을 제공한다.
Lock-free Push and Pop
ABA Problem
Synchronization(동기화)
Message Passing
Synchronization
Sender와 Receiver는 메세지를 전달될때까지 기다리는동안 blocking될 수도있고 안될수도있다.
Addressing
Direct Addressing
Indirect Addressing
Barriers
모든 쓰레드가 특정 지점(Barrier)에 도달할 때까지 기다렸다가 다음단계를 진행하도록 한다.
'cs지식 > 운영체제' 카테고리의 다른 글