int withdraw(account, amount){
balance = get_balance(account);
balance = balance - amount;
put_balance(account, balance);
return balance;
}

각각의 Thread는 ()는 자신의 Register, Stack을 가지고 있고 다른 Thread의 Stack에는 접근할 수 없다.
Code, Data, File을 공유한다.
Process 간의 동기화 (Process Synchronization)
Synchronization restricts the concurrency
(모순적이게도 Concurrency를 해칠 수 밖에...)
Scheduling is not under programmer's control

Mutual Exclusion (상호 배제)
만약 Process A가 Critical Section에 진입해 있다면, 다른 모든 Process는 진입할 수 없어야 함
Progress (진행)
만약 어떤 Process도 Critical Section내에 있지 않고, Critical Section에 진입하려는 Process가 존재한다면, Remainder Section에서 실행 중이 아닌 Process들 (= 진입하려는 Process들) 만이 누가 진입할지 결정할 수 있어야 함 -결정은 무한히 연기될 수 없음 (Deadlock-free)
Bounded Waiting
Process가 Critical Section에 진입할 때까지 걸리는 시간에 Limit이 존재해야 함(Starvation-free)

만족 조건 : Mutual Exclusion
불만족 조건 : Progress, Bounded Waiting
turn=0으로 초기화 된 것이 문제이다.
프로세스 가 언제 실행될지 모르는 상황에서 이 실행되면은 은 무한 루프를 돌고 있다. (Progress, Bounded Waiting 불만족)

그림과 같이 1,2,3,4 순서대로 코드가 실행되버리면, flag[0]와 flag[1]이 모두 true의 값을 가지게 되고 두 프로세스는 무한 루프에 빠져버려 진행되지 않는다.
flag와 turn을 모두 사용하는 방식이지만, turn을 0으로 초기화하지 않음.

만족 조건 : Mutual Exclusion, Progress, Bounded Waiting
하드웨어로 처리하면 알고리즘이 매우 간단하게 됨

boolean TestAndSet(boolean *target){
boolean rv = *target;
*target = true;
return rv;
}
do {
while(TestAndSet(&lock));
critical section
lock = false;
remainder section
}
critical section에 들어오면서 lock을 true로 변경해줌 + return값은 아직 false
do {
waiting[i] = true;
while(waiting[i] == true)
swap(&lock, &waiting[i]);
critical section
lock = false;
remainder section
}
H/W에서 제공하는 Instruction인 TestAndSet()과swap() 연산은 Atomic하기 때문에, Mutual Exclusion과 Progress(Deadlock-free)를 만족하지만, Bounded Waiting 같은 조건은 User Program에서 제공해야 한다.
# Example : Bounded Waiting Solution
// Shared Data
boolean waiting[n];
boolean lock;
do {
waiting[i] = TRUE;
key = TRUE;
while(waiting[i] && key)
key = TestAndSet(&lock);
waiting[i] = FALSE;
// critical section
j = (i + 1) % n; // i 이후의 프로세스들부터 보겠다.
while((j != i) && !waiting[j]) // 순회하면서 waiting = TRUE인 프로세스를 찾음
j = (j + 1) % n; // 순차적으로 다음 프로세스를 본다
if (j == i) // 대기중인 프로세스가 없다면, lock을 해제한다
lock = FALSE;
else
waiting[j] = FALSE; // 대기중인 프로세스가 있다면 해당 프로세스를 critical section으로...
// remainder section
} while (TRUE);
P(Sem) {
while (Sem <= 0);
Sem = Sem - 1;
}
S(Sem) {
S = S + 1;
}
Busy Waiting 방식의 CPU Cycle을 낭비하는 문제를 해결
Semaphore의 자료구조에 Sleep Queue를 추가하여, 대기 중인 Process를 관리
- Semaphore의 값이 양수가 되어 Critical Section에 진입이 가능하게 되면, Sleep Queue에서 대기 중인 Process를 깨워 실행시킴
typedef struct {
int value; // 세마포어 값
struct process *list; // 세마포어를 대기하는 프로세스의 sleep queue
} semaphore;
P(semaphore *S){
S -> value--;
if (S -> value < 0){
add this process to S -> list; // 프로세스를 sleep queue에 삽입
sleep();
}
}
V(semaphore *S){
S -> value++;
if (S -> value <= 0)
remove a process P from S -> list; // 프로세스를 sleep queue에서 꺼내온 후,
wakeup(P); // 실행
}
}
H/W Instruction(TestAndSet) -> Binary Sem -> Counting Sem
# Wait Operation (P)
P(S1);
C--;
if (C < 0){
V(S1);
P(S2);
}
else
V(S1);
# Signal Operation (V)
P(S1);
C++;
if (C <= 0) {
V(S2);
}
V(S1);

P(); -> Critical Section -> P();
Critical Section 후에 Lock을 풀어주는 V()가 없으므로, 한 Process가 Critical Section에 진입하면, 나올 수 없다.
(다른 Process들이 Critical Section에 진입 못하므로 Deadlock 발생)
V(); -> Critical Section -> P();
Critical Section 전에 Lock을 걸어주는 P()가 없으므로, 여러 Process가 동시에 Critical Section에 진입 할 수 있으므로, Mutual Exclusion을 보장 못함

