
⚠️ 해당 포스팅은 인프런 공룡책 강의를 듣고 개인적으로 정리하는 글입니다. 정확하지 않은 정보가 있을 수 있으니 주의를 요합니다.
Chapter 6 CPU Synchronization Tools
int count = 5;
while(true) {
	while(count == BUFFER_SIZE)
    	; /* do nothing */
    
    buffer[in] = next_produced;
    in = (in + 1) % BUFFER_SIZE;
    count++;
}
while(ture) {
	while (count == 0)
 	;	/* do nothing */
        
    next_consumed = buffer[out];
    out = (out + 1) % BUFFER_SIZE;
    count --;
    
    /* consume the item in next_consumed */
}
/* 결과가 6이 나오는 것이 아니라, 4,5도 함께 나오며 제대로된 결과가 출력되지 않음 */
count의 값이 5라고 지정하고 생산자와 소비자가 각각 카운트를 증가시키고 감소시키는 작업을 동시에 수행했을 때 결과가 4나 5, 혹은 6이 나오며 우리가 기대한 결과를 받지 못하게 된다.count++ 과 count-- 는 우리가 작성한 코드에서 보았을 때는 한 줄의 간단한 코드이다.	/* count ++ */
    register1 = count
    register1 = register1 + 1
    count = register1
    
    /* count -- */
    register2 = count
    register2 = register2 - 1
    count = register2
count++ 과 count-- 명령은 로우 레벨 단계에서 임의의 순서로 끼어지게 되며, 순차 실행과 동일한 결과를 낳게 된다.

public class RaceCondition2 {
    public static void main(String[] args) throws InterruptedException {
        RunnableTwo run1 = new RunnableTwo();
        RunnableTwo run2 = new RunnableTwo();
        Thread t1 = new Thread(run1);
        Thread t2 = new Thread(run2);
        t1.start();t2.start();
        t1.join(); t2.join();
        System.out.println("Result : " + RunnableTwo.count);
    }
}
public class RunnableTwo implements Runnable{
    static int count = 0; // 공유 데이터
    // 동시에 접근하며 경쟁 상황(Race condition) 발생
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }
}
/* 결과가 20000이 아니라, 무작위로 나옴. */


데커의 알고리즘 : 두 프로세스 간 문제를 해결하는 방법turn 과 flag 변수로 크리티컬 섹션에 진입할 프로세스 혹은 스레드를 결정한다.public class PetersonTest {
    static int count = 0; // 공유 자원
    static int turn = 0; // 다음 차례 지정
    static boolean[] flag = new boolean[2]; // 실행 스레드 지정
    public static void main(String[] args) {
        Thread pThread = new Thread(new Producer());
        Thread cThread = new Thread(new Consumer());
        pThread.start();
        cThread.start();
        try {
            pThread.join();
            cThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("남은 갯수 : " + count); // 공공재 총량 출력
    }
    static class Producer implements Runnable {
    
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                flag[0] = true; // 나 이제 실행할 준비가 됐어.
                turn = 1; // 내가 실행하면, 다음 차례는 너야
                while (flag[1] && turn == 1) ; // Busy Waiting
                // 너가 이미 실행을 하고 있으면 난 기다릴게
                // 실행을 다 마쳤으니 이제 내 차례고, 난 이제 크리티컬 섹션에 진입할거야.
                count++; // 크리티컬 섹션 조작
                flag[0] = false; // 내 실행을 모두 마쳤어.
            }
        }
    }
    static class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                flag[1] = true; // 나 이제 실행할 준비가 됐어.
                turn = 0; // 내가 실행하면, 다음 차례는 너야.
                while (flag[0] && turn == 0) ; // Busy Waiting
                // 너가 실행중이면, 난 기다릴게.
                // 실행을 다 마쳤으니 이제 내 차례고, 난 이제 크리티컬 섹션에 진입할거야.
                count--; // 크리티컬 섹션 조작
                flag[1] = false; // 내 실행을 모두 마쳤어.
            }
        }
    }
}
busy waiting)를 돌게 되는데, 무한 루프에도 CPU 자원을 사용하기 때문에 CPU를 효율적으로 사용하지 못하는 문제가 있다.
이게 무슨소리야? -> a++ 은 아까 보았듯이 기계어 세 줄로 이루어져 있는데, 이를 기계어 한 줄로 줄여 중간에 인터럽트 되는 상황을 막겠다는 이야기이다.test_and_set() 명령어와 compare_and_swap() 명령어로 예를 들어 설명해본다.	boolean test_and_set(boolean *target) {
    	boolean rv = *target;
        *target = true;
        
        return tv;
    }
    
    do {
    	while (test_and_set(&lock)); /* do nothing, context switching X */
		// 본인의 lock 을 true 로 만들고 진입한다.
        
		/* critical section */
        
        lock = false; // 크리티컬 섹션을 빠져나온 후 false로 만들어 다른 프로세스 진입을 허용
        
        /* remainer section */
    	
    } while (true);
	int compare_and_swap(int *value, int expected, int new_value) {
    	int temp = *value;
        
        if (*value == expected)
        	*value = new_value;
          
        return tmp;
    }
    
    while (true) {
    	while (compare_and_swap(&lock, 0, 1) != 0);
        /* do nothing */
        
        /* critical section */
        
        lock = 0;
        
        /* remainer section */
    }
import java.util.concurrent.atomic.AtomicBoolean;
public class PetersonTest2 {
    static int count = 0;
    static int turn = 0;
    static AtomicBoolean[] flag; // 원자 변수
    static {
        flag = new AtomicBoolean[2];
        for (int i = 0; i < flag.length; i++)
            flag[i] = new AtomicBoolean();
    }
    public static void main(String[] args) {
        Thread pThread = new Thread(new PetersonTest2.Producer());
        Thread cThread = new Thread(new PetersonTest2.Consumer());
        pThread.start();
        cThread.start();
        try {
            pThread.join();
            cThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("남은 갯수 : " + count); // 공공재 총량 출력
    }
    static class Producer implements Runnable {
        @Override
        public void run() {
            for (int k = 0; k < 100000; k++) {
                
                /* entry section */
                flag[0].set(true);
                turn = 1;
                while (flag[1].get() && turn == 1); // 원자 변수 특정 명령어 
                
                /* critical section */
                count++;
                
                /* exit section */
                flag[0].set(false);
                
                /* remainder section */
            }
        }
    }
    static class Consumer implements Runnable {
        @Override
        public void run() {
            for (int k = 0; k < 100000; k++) {
                
                /* entry section */
                flag[1].set(true);
                turn = 0;
                while (flag[0].get() && turn == 0)
                    ;
                
                /* critical section */
                count--;
                
                /* exit section */
                flag[1].set(false);
                
                /* remainder section */
            }
        }
    }
}