일반적으로 프로세스들은 각자 하나의 주소공간이 있다.(Virtual Memory) 따라서 Race Condition이 발생하지 않는다.
그러나 공유 자원에 접근하는 경우에 Race Condition이 발생한다.
S-box(메모리 주소공간)를 공유하는 E-box(CPU 프로세스)가 여럿있는 경우 Race Condition의 가능성이 있다.
Multiprocessor System에서 하나의 메모리를 각각의 CPU가 공유하고 있다면 하나의 CPU가 A데이터를 읽어간 동안에 또 다른 CPU가 A데이터를 읽어가는 경우이다.
여러 프로세스나 커널 쓰레드가 커널 내부 데이터에 동시에 접근할 때도 경쟁 상태가 발생할 수 있다.
전부다 커널 데이터와 관련(공유자원)
갑자기 인터럽트가 발생했는데 이 인터럽트 처리루틴이 동일한 공유 데이터에 접근하는 경우이다(기본적인 상황)
해결점: 먼저 하던일 다 끝내기 전까지 인터럽트를 받아들이지 않는것이 Race Condition의 해결점이다.
해결점: 프로세스가 커널모드에 있을때는 할당시간이 끝나도 CPU를 뺏기지 않도록 한다.
해결점1: 커널 전체에 락을 거는 방법
한번에 하나의 CPU만이 커널에 들어갈 수 있다. lock을 걸고 데이터를 변경, 데이터 변경 후 lock을 푼다.
해결점2: 공유 데이터별로 락을 건다(Detail)
커널 내부에 있는 각 공유데이터에 접근할때마다 그 데이터에 대한 lock/unlock을 하는 방법
공유데이터의 동시 접근은 데이터의 불일치 문제(inconsistency)를 발생시킨다.
일관성 유지를 위해서는 협력 프로세스 간의 실행순서를 정해주는 메커니즘 필요(접근막음)
하나의 프로세스가 critical section에 있을때 다른 모든 프로세스는 critical section에 들어갈 수 없어야 함 -> 기다려야 한다.
do{
entry section; //critical section으로 들어감(lock을 건다.)
critical section;
exit section;//critical section에서 나옴(lock을 푼다.)
remainder section;
}while(1);
1) 상호 배제(Mutual Exclusion)
: 프로세스가 Critical Section에 들어가 있으면 다른 프로세스는 Critical Section에 못 들어감
2) 진행(Progress)
: Critical Section에 아무도 들어가 있지 않은 상황에서 내가 들어가고 싶어하면 넣어줘야 함
3) 유한 대기(Bounded Waiting)
: 특정 2개의 프로세스가 번갈아가면서 critical section에 들어가서 나머지 1개의 프로세스가 critical section에 들어가지 못하는 상황일때 횟수의 한계를 준다.
turn=0 -> p0프로세스
turn=1 -> p1프로세스
int turn;
turn=0;
do{
while(turn!=0);
critical section
turn=1;
remainder section
}while(1);
내 차례가 아닌동안에는 while문 돌면서 기다린다(turn이 0이 아닌경우)
그러나 turn이 0이 되면 critical section으로 들어간다.
critical section에서 나오면 상대방 차례(p1)으로 바꿔준다.
문제점: 상호 배제는 만족하지만 진행이 만족되지 않는다.
이 알고리즘은 두 프로세스가 동시에 critical section에 들어가려고 할 때, 하나의 프로세스가 반드시 다른 프로세스가 나올 때까지 기다려야 한다.
따라서 프로세스 0이 크리티컬 섹션에 들어갔다가 빠져나오면서 turn을 1로 바꿔도 고정으로 turn!=0을 박아 놓았기 때문에 프로세스 1(turn=1)이 무한대기상태에 빠진다.
따라서 고정된 상수가 아니라 flag 변수로 설정하는 것이 필요함!
boolean flag[2];
initially flag[모두] = false; // 처음은 모두 들어가고 싶은 상태가 아니다.
do{
flag[i] = true; // 자기가 들가고 싶으면 자신의 flag true로 만든다.
while(flag[j]); // 상대방 flag면 무한반복
critical section
flag[i]=false; // 나올때 자신의 flag를 false로 바꿈
remainder section
}while(1);
문제점: pi가 flag를 든 상태에서 CPU를 뺏긴다. pj가 CPU를 받아서 자신의 flag를 든다. ciritical section에는 들어가지 못하고 깃발만 2개인 상황이 된다.
즉 상대방이 문맥교환으로 CPU를 가지게 되면 깃발이 2개여서 둘다 critical sectin에 진입하지 못하게 된다.
CPU를 뺏기는 타이밍은 다 읽고 이제 쓰려고 할때 뺏긴다.
중간에 CPU를 뺏길 수 있음을 고려해서 알고리즘을 짰다.
turn과 flag가 모두 등장
do{
flag[i] = true; // 깃발을 들어서 의사표현
turn = j; // turn을 상대방 turn으로 바꿈
while(flag[j] && turn==j); // 상대방이 깃발을 들고있고, 상대방의 차례인지 체크(turn)
critical section // 아니라면 내차례이므로 진입
flag[i]==false; // 마치고 깃발내림
remainder section
}while(1);
앞의 3가지 조건을 모두 만족한다.
그러나 Busy Waiting의 문제점이 있다(while 루프)
데이터를 읽는 것, 데이터를 쓰는것을 하나의 인스트럭션으로 처리할 수 없기에 문제가 발생했던 것이다.
다읽고 이제 쓰려고 할때 뺏기는거지 읽는 도중에 뺏기지는 않는다.
만약 하나의 인스트럭션으로 위에것이 실행가능 하다면 적어도 인스트럭션 하나가 실행되는 도중에 CPU를 빼앗기지 않는다. (Test_and_set이 하나의 인스트럭션)
진입할떄는 lock을 true로 바꾸고 진입한다.