왜 이사람이 7주차가 끝날 때 까지도 글을 안올렸나 하실겁니다.
사실 별 이유는 없습니다..
간단하게 변명을 해보자면, 4주차부터는 심적여유가 정말정말 없었습니다.
4주차는 red-black tree를 구현하기 위해 c언어 공부를 하여야 했고, c언어를 포기하다시피 하던 저는 강제적으로 c언어를 공부하여야 했기 때문에 팀원들과 Single-Linked List, Doubly-Linked List 및 binary-search Tree를 직접 C언어의 포인터 및 구조체를 사용하여 구현해보면서 곧바로 red-black tree에 진입하여 정신이 없었습니다.(변명입니다.)
5주차는 Malloc-Lab을 진행하였고, 6주차는 web-server, proxy 구현(C)를 진행하였는데, 4주차와 비슷한 이유로 블로그 작성을 못했습니다.. 하지만 공부 내용은 따로 마크다운언어로 저장을 해 놨으니 pintos주간이 끝나는 날 tistory에 블로그 이사를 함과 동시에 순차적으로 공부 내용을 작성하도록 하겠습니다.
(5주차) (여기서 buddy system은 extra test입니다)
CPU가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치나 예외상황이 발생하여 처리가 필요한 경우에 마이크로프로세서에게 알려 처리할 수 있도록 하는 것을 말함.
인터럽트는 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 나뉨.
Interrupt process
1. process A는 system call을 통해 인터럽트 발생.
2. CPU는 현재 진행중인 기계어 코드를 완료.
3. 현재까지 수행중이었던 상태를 해당 process의 PCB에 저장.
4. PC에 다음에 실행할 명령의 주소를 저장.
5. 인터럽트 벡터를 읽고 ISR주소값을 얻어 ISR(Interrupt service routine)로 점프하여 루틴을 실행.
6. 해당 코드를 실행.
7. 해당 일을 다 처리 하면, 대피 시킨 레지스터를 복원.
8. ISR의 끝에 IRET명령어에 의해 인터럽트가 해제.
9. IRET 명령어가 실행되면, 대피시킨 PC값을 복원하여 이전 실행위치로 복원.
락은 여러 스레드 간에 자원을 접근하는 매커니즘을 제공. 일반적으로 상호 배제 정책(semaphore)을 통해, 하나의 스레드가 특정 자원에 접근중인 경우에는 다른 스레드가 접근하지 못하도록 제한함. 락이 없다면 두 개 이상의 스레드가 동시에 자원에 접근할 수 있으므로, 데이터의 무결성이 보장되지 않음. 락의 개념은 멀티스레드를 사용하는 환경이라면 어디든 사용 가능.
락이 필요한 예시 - 여러 스레드가 동시에 공유 자원에 접근하는 경우.
=> 여기서 'x를 1 증가시킴'라는 작업은 기계어 상으로
1. x를 읽는다 - (메모리로부터 x를 읽어 레지스터에 저장)
2. x를 1 증가시킨다 - (레지스터를 1 증가시킴)
3. 증가된 값을 x에 저장 - (레지스터의 값을 x에 저장)
x를 1이라고 해보자. A와 B가 동시에 x를 읽고, 동시에 증가시키고 동시에 쓴다면 x는 2가됨.
=> 분명히 연산은 두 번을 했는데, 증가는 한번만 된 것.
비슷하게 은행송금을 예로 들 수 있음. 송금을 x에서 y로 한다면 다음의 순서일 것.
1. x의 돈이 충분한지 확인.
2. x의 돈을 송금한 금액만큼 뺌.
3. y의 돈을 송금한 금액만큼 더한다.
x의 계좌에는 1000원이 있고, 그걸 y에게 1000원을 송금한다고 하면 다음과 같은 상황 발생.
스레드 A | 스레드 B
x의 돈을 확인(1000원) | x의 돈을 확인 (1000원)
x의 돈을 0원으로 설정(-1000) |
y의 돈을 1000원 더함 | x의 돈을 0원으로 설정 (-1000)
| y의 돈을 1000더함
=>위의 예제에서 스레드 A와 B간의 동기화 문제를 해결하려면 송금의 연산(돈 확인 => 돈을 뺌 => 돈을 더함)을 하나의 연산으로 묶어주면 됨. 이러한 연산을 원자적 연산 (Atomic Operation)이라고 하는데, 연산을 실행하는 도중에 다른 연산이 간섭하지 않는다는 의미.
아까의 상황에서는 스레드 A가 돈을 확인하는 도중에 스레드 B가 중간에 끼어들어서 원자적인 연산이 아니었지만, 돈 확인 => 돈을 뺀다 => 돈을 더한다 라는 세개의 연산이 끝나기 전까지 다른스레드가 끼어들지 못하게 한다면 이 문제를 해결할 수 있음.
여기서 나오는 개념이 바로 Critical Section임. 쉽게말해 일종의 보호구역 으로서, Critical Section안에서만 공유자원에 접근하도록 하고, 동시에 하나의 스레드만 들어올 수 있게한다면 위에서 말한 원자성을 보장할 수 있음. 위의 예시에서는 돈 확인 - 돈을 뺀다 - 돈을 더한다 라는 일련의 작업들을 하나의 Critical Section으로 지정해 줄 수 있음.
락을 통해 Critical Section의 범위를 지정해줄 수 있음. 락을 잠가(획득, acquire)버려서 다른 스레드가 접근하지 못하도록 한다면, 그게 Critical Section이 시작되는거고, 락을 풀어서(release) 다른 스레드가 Critical Section에 접근 가능하도록 한다면 그게 Criticala Section이 끝나는것임.
------Critical Section 시작--------
lock (acquire)
1. x의 돈이 충분한지 확인.
2. x의 돈을 송금한 금액만큼 뺌.
3. y의 돈을 송금한 금액만큼 더함.
unlock (release)
-----Critical Section 종료---------
락을 생성하고, 소멸하는 것부터 락을 획득하고 반환하는등 락을 사용하면 오버헤드가 생김.
그래서 락을 사용할 때는 항상 어느정도의 비용이 발생함. => 락을 많이 사용할 수록 락 오버헤드가 많아짐. 실제 연산보다 락 자체를 사용하는데 드는 비용이 커지는것임.
Contention은 투쟁, 논쟁 등을 의미하는데, lock을 획득하고자 하는 스레드가 2개 이상인 경우, 서로 경쟁하게 되며 경쟁으로 인해 락을 더 획득한 스레드와 덜 획득한 스레드가 생기게 됨. 심한경우 다른 스레드들이 10번 락을 획득하는동안 경쟁에 밀려서 1번도 락을 획득하지 못하는 기아상턔(Starvation)의 스레드가 생길 수 있음. 이런 상황을 바람직하지 않으며, 모든 스레드가 공정하게 같은 비율로 락을 획득하는것이 가장 이상적임.
Granularity(세분성)은 락이 얼마나 광범위한지, 또는 세밀한지를 의미. 락의 개수가 적을수록 lock/unlock을 하며 발생하는 오버헤드는 줄어들겠지만 광범위한 만큼 스레드간의 경쟁이 중요해진다. 반대로 락이 매우 작은 범위를 감싸고 락의 개수가 많을수록 오버헤드는 증가하지만 경쟁은 완화됨. 상황에 맞춰 락의 적절한 범위를 결정해야함.
데드락은 스레드들이 서로 락을 대기하느라 프로그램이 멈추는, 교착 상태에 빠지는것을 의미.
유명한 문제로 식사하는 철학자 문제가 있음. 원형 탁자에 N명의 철학자들이 앉아있고, N개의 포크가 철학자의 왼쪽과 오른쪽에 존재한다. 스파게티를 먹으려면 2개의 포크 (자신의 왼쪽, 오른쪽)가 필요한데, 그렇다면 왼쪽 포크 대기 - 왼쪽 포크 획득 - 오른쪽 포크 대기 - 오른쪽 포크 획득과 같이 포크 2개를 획득하는 과정이 있을것임. 그런데 여기서 모든 철학자가 동시에 왼쪽 포크를 획득한다면 영원히 오른쪽 포크를 대기하며 교착상태에 빠지게 됨. 락을 사용할 때는 이러한 교착 상태를 초기에 방지해야 함.
=> 두 개 이상의 작업이 서로 상대방의 작업이 끝나기만을 기다리고 있기 때문에 결과적으로 아무것도 완료되지 못하는 상태.
우선 이 정도까지가 7주차에 배운 내용을 간략하게 정리해놓은 내용입니다.
추후 Tistory로의 이동 시에 자세하게 차근차근 설명하는 내용을 올리도록 하겠습니다.
이사 후엔 열심히 올리도록 노력해보겠습니다.. 꼬옥..!!
긴 글 읽어주셔서 감사합니다!