2022-12-16, 2022-12-17
PintOS 프로젝트 - 쓰레드와 동시성
참고: https://omscs.gatech.edu/cs-6200-introduction-operating-systems-course-videos
무엇?
- 쓰레드는 무엇인가?
- 쓰레드는 장난감 샵의 일꾼!
- 이 일꾼은 능동적인 주체다
- 장난감 주문을 위한 일을 한다 = 쓰레드는 프로세스를 수행한다
- 다른 일꾼들과 동시에 일한다 = 많은 쓰레드는 동시에 일한다(동시성의 개념)
- 다른 일꾼들과 동시에 일할 때 협업이 필요하다
- 효율적으로 일하기 위해, 도구, 일하는 공간, 부품 등을 서로 공유한다 == I/O 기기, CPU, 메모리 등을 공유한다
→ 어떤 쓰레드가 이러한 자원에 접근할 수 있는지 어떻게 결정할까?
- 효율적으로 일하기 위해, 도구, 일하는 공간, 부품 등을 서로 공유한다 == I/O 기기, CPU, 메모리 등을 공유한다
- 이 일꾼은 능동적인 주체다
- 쓰레드는 장난감 샵의 일꾼!
- 스레드와 프로세스는 어떻게 다른가?
- 어떤 자료구조가 쓰레드를 관리하기 위해 사용되는가?
운영체제의 큰 그림
참고: https://www.youtube.com/watch?v=BoJ1eaE5F-I&list=PLVsNizTWUw7FCS83JhC1vflK8OcLRG0Hl&index=27
왜?
운영체제는 왜 존재할까?
운영체제는 어떤 역할을 할까?
운영체제를 왜 배워야 할까?
무엇?
- 커널이란?
- 운영체제의 핵심 서비스를 담당하는 부분
- UI는 운영체제에는 속하지만 커널에는 속하지 않음
- 시스템 콜과 이중 모드란?
- 시스템 콜(=시스템 호출)
- 사용자가 실행하는 프로그램은 자원에 직접 접근할 수 있을까? NO! 자원에 직접 접근은 위험하다!
- 응용 프로그램이 자원에 접근하려면 운영체제에 도움을 요청(=운영체제의 코드를 실행)해야 함
- 이러한 자원 접근 제한은 이중모드로 구현이 된다
- 이중모드: CPU가 명령어를 실행하는 모드를 크게 사용자 모드와 커널 모드 두 가지로 구분하는 방식
- 사용자 모드:
- 운영체제 서비스를 제공받을 수 없는 실행모드
- 커널 영역의 코드를 실행할 수 없는 실행 모드
- 자원 접근 불가
- 커널 모드:
- 운영체제의 서비스를 제공받을 수 있는 실행 모드
- 자원 접근을 비롯한 모든 명령어 실행 가능
- 어떤 모드인지 CPU가 어떻게 알 수 있을까?
- 플래그 레지스터에 슈퍼바이저 플래그 → 1인 경우 커널 모드, 0일 경우 사용자 모드
- 언제 커널 모드, 사용자 모드로 바뀔까?
- 시스템 호출을 하면 커널 모드로 전환 됨 → 일종의 소프트웨어 인터럽트
- 시스템 콜(=시스템 호출)
- 운영체제의 가장 핵심적인 서비스는?
- 프로세스 관리
- 프로세스(or Task) == 실행 중인 프로그램
- 수많은 프로세스들이 동시에 실행 → 동시다발적으로 생성/실행/삭제되는 다양한 프로세스를 일목요연하게 관리
- paging, swapping을 통해 모든 프로세스를 메모리에 다 올리지 않고서도 실행할 수 있음
- 자원 접근 및 할당
- CPU
- 메모리(페이징, 스와핑)
- 입출력장치(인터럽트 서비스 루틴 )
- 파일 시스템 관리
- 보조저장장치의 정보 덩어리를 파일이라는 단위로 묶어서 저장
- 파일을 묶은 단위를 폴더, 디렉토리
- 프로세스 관리
CPU 인터럽트란?
참고: https://www.youtube.com/watch?v=V4lp6iGoUFY&list=PLXvgR_grOs1DGFOeD792kHlRml0PhCe9l&index=5
무엇?
왜?
인터럽트 개념 개요 잡기.
2022-12-18
프로세스와 스레드
참고: https://www.youtube.com/watch?v=2i3dInwVeUM&list=PLXvgR_grOs1DGFOeD792kHlRml0PhCe9l&index=10
https://www.youtube.com/watch?v=x-Lp-h_pf9Q
무엇?
- 프로세스와 스레드의 차이
왜?
프로세스와 쓰레드는 어떻게 다르고, 어떤 맥락에서 등장하는 걸까?
프로세스 상태(휴식, 보류)와 문맥 전환(context switching)
참고: https://www.youtube.com/watch?v=a2GDsaReFEA&list=PLXvgR_grOs1DGFOeD792kHlRml0PhCe9l&index=11
무엇?
- 프로세스의 대기 상태
- 휴식 sleep: 자발적. 나 자러 갈게.
- 인수로 정해준 시간 이후에(e.g.: 10ms) 대기열에 재진입 → 앞 애들이 끝나야 얘가 다시 실행 됨 ⇒ 실제로 걸리는 시간은 인수로 정한 시간 + α
- 보류 suspend: 외부 요인(OS나 다른 프로그램)에 의해 의도 되지 않게 대기하는 상태. 너 비켜봐봐.
- e.g.: 스왑 날때(메모리에 있던 거를 디스크로 옮길 때 )
- 휴식 sleep: 자발적. 나 자러 갈게.
- 휴식, 보류가 되면 ready-queue에서 이탈하게 됨 -> CPU 쓸 생각 없다는 것
왜?
프로세스의 상태 변화는 어떻게 이루어질까?
그리고 그 때 어떤 일이 발생하는지.
프로세스 생성과 복사 fork()
와 exec()
참고: https://www.youtube.com/watch?v=RzN18na94Wc&list=PLXvgR_grOs1DGFOeD792kHlRml0PhCe9l&index=12
https://woochan-autobiography.tistory.com/207
무엇?
- fork() : 부모 프로세스를 복사하여 자식 프로세스를 생성
- exec() : 새로운 프로세스를 생성하지 않으며, exec()를 호출한 프로세스가 새로운 프로세스의 코드로 덮여 쓰어지며 대체 됨. 프로세스 아이디가 같음. (fork보다 더 효율적)
왜?
가상메모리 할 때 한번 노트했던 부분.
프로세스 개념을 공부하다보니 fork와 exec 함수가 자주 나오는데 정확히 어떤 개념인지 궁금해졌다.
멀티스레딩과 동기화 기본
참고: https://www.youtube.com/watch?v=y60nIDJAyJQ&list=PLXvgR_grOs1DGFOeD792kHlRml0PhCe9l&index=13
Process Explorer 다운로드
무엇?
- 프로세스와 쓰레드의 구분 (※ 프로세스와 스레드 노트 참고 )
- 다중 프로세스 = 멀티 태스킹
- 다중 쓰레드 = 멀티 쓰레딩
- 멀티 쓰레딩 vs 멀티 프로세스?
- 효율 측면에서 멀티 쓰레딩이 더 효율적일 수 있음 → 멀티 프로세스 조건은 각각 VMS를 부여해주어야 하므로
- 동기화 이슈
- 쓰레드는 연산의 단위 → CPU는 쓰레드가 선점한다. (다만 권한은 OS가 프로세스에게 부여함 )
- 쓰레드들은 각기 다른 연산을 하면서 흐름이 다르기 때문에, 동기화가 중요한 이슈임
- 동기화란?
- CPU 스케줄링에서 동기화란 경쟁 조건을 막고 프로그램의 정확한 작동을 보장하기 위해 다양한 쓰레드나 프로세스를 조정하는 것을 말한다. 다양한 동기화 메커니즘을 통해 달성될 수 있는데, 예를 들면 lock, 세마포어, 조건 변수 같은 것이다.
- 한 프로세스의 쓰레드들은 VMS 안의 공유 자원을 두고 경쟁한다 ∴멀티쓰레딩을 얘기할 때 전역 변수 등에 대해서 접근할 때 race condition 등이 발생하면서 예측이 어려워짐. → 우연에 기대게 된다. → 이러한 예측 불가능, 우연에 맡기는 코드는 그렇게 좋지 않다.
- race condition (경쟁조건, 프로세스 안의 공유 자원을 선점하려는 상황; e.g. 프로세스 가구 내의 화장실을 선점하려는 상황)
- 쓰레드도 프로세스처럼 상태가 존재. 슬립, 대기 모드 → 모든 프로세스는 적어도 1개 이상의 스레드를 가지고 있으며, 사실은 스레드가 대기, 실행 되는 것.
- 쓰레드의 종료 이벤트를 대기하는 방식으로 동기화를 다룰 수 있다 (리눅스, 유닉스에서는 시그널, 윈도우에서는 이벤트)
- 그 외
- 쓰레드는 각자 따로 논다
- 단순 대입 연산은 코어가 서로 섞이지 않음. (atomic한 연산을 보장)
- sleep(0) -> 대기열에 빠져서 뒤로 가겠다
왜?
PintOS의 project 1의 주요한 구현 과제 중 하나인 동기화.
동기화는 왜 필요할까?
2022-12-19
CPU 스케줄링 개요
참고: https://www.youtube.com/watch?v=DK_tugBjxj8
무엇?
- OS와 프로세스(스레드)는
- 식당 관리자 = OS
- 손님 = Process(thread)
- 식당 관리자(OS)는 유저 프로그램이 잘 돌아가도록 도와주기 위해 존재함.
- CPU 스케줄링의 목적 : 시스템 과부하 상태를 막겠다
- 스케줄링의 단계
- 고수준: 작업 스케줄링 = job 스케줄링, 프로세스를 묶은 단위, 손님 수 조절(정원을 벗어난 애들 대기세우기 )
- 중간수준
- 저수준 : 각 손님의 주문, 요리 제공 순서를 미세하게 조절하는 단계(프로세스와 쓰레드가 CPU를 선점해서 작동하게 하는 것 )
- 스케줄링 시 고려사항 (스케줄링 알고리즘)
- 선점형 스케줄링 preemtive: 일반적인 경우. (e.g. 엑셀이 시작해도 워드를 써야할 때가 되면 OS가 엑셀을 웨잇시킬 수 있음)
- 비선점형 스케줄링 non-preemtive: 일단 일이 시작되면 되돌릴 수 없음. (e.g. 엑셀이 끝날때까지 워드는 기다려야 함) 이런 건 언제 사용하지?
- 프로세스/스레드의 우선순위
- 쓰레드별로 우선순위를 정함 - 보통의 경우 5단계
- 일반적으로 프로세스 띄우면 보통으로 출발
- 우선 순위를 적용한 스케줄링은?
- 압축 해제 같은 경우, 20분 걸리나 25분 걸리나 차이 없으므로 우선순위 낮게 됨(운영체제, 입출력 중심, 백그라운드)
- 미디어 플레이어(동영상 플레이어)는 우선순위 높게해서 안 끊기게.(포어그라운드, 전 프로세스. 눈에 잘 보이는 GUI가 끊기거나 하면 굉장히 화가 많이 난다!)
- 서버같은 경우, 백그라운드 서비스에 우선순위를 더 줌(입출력이 기본이라 )
왜?
CPU 스케줄링과 우선순위 개념이 궁금.
스핀락(spinlock) 뮤텍스(mutex) 세마포(semaphore) 각각의 특징과 차이
참고: https://www.youtube.com/watch?v=gTkvX2Awj6g
무엇?
- 락
- 임계구역critical section: 단독의 쓰레드, 혹은 프로세스만 접근할 수 있는 영역 (락을 얻어야 접근할 수 있고, 할일이 끝나면 락을 반환(언락)하여 다음 쓰레드, 프로세스가 사용할 수 있게 함 )
- atomic 명령어란; 실행 중간에 간섭받거나 중단되지 않음. 같은 메모리 영역에 대해 동시에 실행되지 않음.
- 스핀락: 락을 가질 수 있을때까지 반복해서 시도 -> CPU 낭비 -> 뮤텍스
- 뮤텍스: 락을 가질 수 있을때까지 휴식 (큐를 이용)
- 세마포어: 시그널 메커니즘을 가진, 하나 이상의 프로세스 .스레드가 임계 구역에 접근 할 수 있도록 하는 장치
- 뮤텍스 코드와 거의 동일.
- lock -> wait
- unlock -> signal
- wait과 signal 사이의 일이 실행된다 ! -> wait과 signal이 서로 다른 프로세스에서 실행될 수 있고, 그러면 프로세스간의 일의 순서를 정해줄 수 있음.
- -> 시그널 메커니즘을 가진다
왜?
세마포어의 개념에 대해서 궁금.
2022-12-20, 2022-12-21
PintOS - Thread; Alarm Clock
참고: https://oslab.kaist.ac.kr/pintosslides/
https://www.youtube.com/watch?v=myO2bs5LMak
무엇?
- 슬립 리스트 정렬하기
슬립 리스트를 불러올 때마다 local_tick 값에 따라 오름 차순 정렬 확인할 때마다 정렬하면 비효율적…→list_inserted_ordered
를 이용해서 sleep_list에 원소 삽입
- 리스트 원소 비교하는 함수
cmp_wakeup_tick
(Returns true if A is less than B, or false if A is greater than or equal to B.) 리스트의 필드를 인자를 받아 인자에 따라 비교하게 만들면? (e.g. t->{필드변수명})→ 조금 구현이 복잡할 거 같다!- 변수
- A의 local tick
- B의 local tick
- 알고리즘
- 리스트가 비어있거나 원소 하나면 ?→ 이미 기본 코드에 에러 처리가 되어 있음
- 어떡하지?
- 아니면
- A < B : true
- A >= B : false
- 리스트가 비어있거나 원소 하나면 ?→ 이미 기본 코드에 에러 처리가 되어 있음
- 변수
- modified thread_sleep
- list insert ordered
- 최소 wake_up tick 찾기
- 최소 웨이크업 틱을 next_tick_to_awake로 업데이트
처음에 아래 1,2 를 하나의 함수로 묶으려고 했으나, 일단 ppt대로 해봄
- 최소 틱을 가진 스레드 저장하는 함수 (
update_next_tick_to_awake
)- 틱을 받아서
next_tick_to_awake
변수에 저장
- 틱을 받아서
global tick→next_tick_to_awake
반환하는 함수 (get_next_tick_to_awake
)sleep list의 맨 앞 요소의 local tick을 반환→ 현재 next_tick_to_awake 값을 반환
global tick→next_tick_to_awake(ticks)
을 이용한 wakeup- next_tick_to_awake와 현재 ticks 비교
cpu 인터럽트 off(슬립 리스트에 원소 추가 되는거 방지? → 바로 실행할 애가 아니기 때문에 굳이 할 필요가 없다 )- while ntta <= 현재 tick
- 슬립 리스트의 맨 앞 요소의 상태를 블럭에서 레디로 바꾸기
- 다음 요소의 tick = global tick
- ▽ 수정한 거(기본 코드의 else 절만 바꿈 )
- 슬립 리스트의 마지막 원소에 도달할 때까지
- 만약 쓰레드의 틱이 현재 틱보다 작거나 같다면
- 슬립 리스트에서 제거
- 스레드 언블락
- 아니라면
- 깨울 시간이 되지 않은 해당 쓰레드의 틱을 최소 틱으로 저장
- 브레이크하여 while문 탈출
- 만약 쓰레드의 틱이 현재 틱보다 작거나 같다면
- 슬립 리스트의 마지막 원소에 도달할 때까지
cpu 인터럽트 on
왜?
list front, list head, list begin, list entry의 차이는 뭘까 …?
→ list front, flist begin은 리스트가 empty일때 사용할 수 있는지 없는지 에러 처리에 차이가 있었다.
PintOS - Thread; Priority Scheduling
참고:https://www.youtube.com/watch?v=myO2bs5LMak
무엇?
-
현재의 핀토스
- fifo 스케줄링 → 우선순위에 따라 cpu를 선점하지 못함!
-
중요한 키워드
- priority inversion : 높은 우선순위를 가진 프로세스가 낮은 우선 순위를 가진 프로세스를 기다리고 있는 것
- → priority donation: priority inversion을 해결할 하나의 방법. 프로세스의 우선순위를 락 홀더에게 물려줌. 더 높은 프로세스가 락을 요청했을 때, 실행중인 프로세스에게 그 높은 우선순위를 물려줌. 따라서 실행중인 프로세스는 계속 실행되고, 그 이후에 그 다음 요청했던 프로세스가 실행 됨.
- Nested Donation: 우선순위를 연속적으로 물려 받게 되는 것.
- multiple donation : 여러개의 락을 T1이 갖고 있을 때, C가 락을 가지면서 나머지 락을 요청하는 프로세스 중 높은 우선순위로 T1의 우선순위가 업데이트 되어야 함.
- Multiple Donation을 위한 자료구조(
Donations
: list of donors): 쓰레드가 donors의 리스트를 유지해야 한다! lock을 해제시킬 때마다, 자신의 donor 중에 가장 큰 우선권을 가진 애를 찾아야 함. (list max 이용하면 될까?, 자신의 원래 프라이어리티를 저장할 필요가 있음) - nested donation을 위한 자료구조(
wait_on_lock
: lock that it waits for): 각 쓰레드가 기다리고 있는 lock을 표시함. 일단 우선순위를 누군가에게 물려주면, 현재의 우선순위를 자식에게 물려줘야 하는지 체크해야 함. 구현 완전히 이해 안 됨
-
요구사항
- 레디 리스트를 우선순위로 정렬하여, 레디 리스트에서 쓰레드를 꺼낼 때 우선순위가 높은 것을 꺼낼 수 있도록 하기
- preemtion (선점) 구현
- 새 쓰레드를 레디 리스트에 넣을 때(타이머 인터럽트가 호출될 때마다 말고 ), 실행 중인 쓰레드의 우선순위와 새 쓰레드의 우선순위를 비교한다
- 실행중인 스레드보다 새로 레디 리스트에 들어온 스레드가 더 높은 우선순위를 갖고 있으면, 새롭게 삽입된 스레드를 스케줄링한다.
- 동기화 primitive - lock, 세마포어, condition variable
- 동기화 primitive를 위해 wait 리스트 정렬 (세마포어, condition variable )
- lock, semaphore, condition variable을 기다리고 있는 쓰레드들의 대기 리스트에서 쓰레드를 선택할 때, 가장 높은 우선순위를 가진 쓰레드를 선택하여 CPU를 사용하도록 한다.
- 동기화 이슈 - priority inversion
- Priority donation 구현
- Multiple donation 구현
- Nested donation 구현
-
기존 존재하는 함수들
thread_set_priority
thread_get_priority
-
todo
- 레디 리스트를 우선순위로 정렬하여, 레디 리스트에서 쓰레드를 꺼낼 때 우선순위가 높은 것을 꺼낼 수 있도록 하기
-
- preemtion (선점) 구현
-
- 슈도코드
- cpu 인터럽트 on/off 필요한가? → 포인터로 현재 쓰레드를 받아오는거기 땜에 안해도 될거 같다고 함
- 러닝 쓰레드의 우선순위를 새로운 우선순위로 지정
cmp_priority
를 쓴다면 a = 러닝 쓰레드의 우선순위, b = 새로운 우선순위- 러닝 쓰레드의 우선순위가 ready_list의 가장 높은 우선순위보다 높다 (return 이 1이다 )
- return
- 러닝 쓰레드의 우선순위가 더 낮다 → 실행 중지 후 레디 리스트로 넣음
- 러닝 쓰레드 yield (이 안에서 do schedule)
- 슈도코드
-
- 슈도 코드
- thread_unblock
- test_max_priority 함수 추가
- 슈도 코드
-
- 동기화 primitive - lock, semaphore, condition variable
-
- 동기화 이슈 - priority inversion 방지를 위한 Priority donation, Multiple donation, Nested donation 구현
-
-
-
- 슈도코드
- 러닝 쓰레드 불러옴
- 러닝 쓰레드가 기다리고 있는 락 선언
- 그 락의 홀더 → 홀더의 wait_on_lock
- 반복문으로 우선순위 도네이션
- 슈도코드
-
-
-
-
-
- 레디 리스트를 우선순위로 정렬하여, 레디 리스트에서 쓰레드를 꺼낼 때 우선순위가 높은 것을 꺼낼 수 있도록 하기
-
테스트 케이스
- semaphore TC
- donation TC
- semaphore TC
쓰레드와 프로세스의 차이 & 쓰레드를 사용하는 이유
참고:
왜?
리눅스는 프로세스 단위로 실행되고, 윈도우 OS는 스레드 단위로 실행된다고 한다.
이는 OS 설계 철학의 차이이며, 무엇이 좋고 나쁘고가 없다고 한다.
각 디자인의 목적이 뭘까? (왜 프로세스 단위 대신 스레드 단위를 사용할까?)
무엇?
스레드와 프로세스는 모두 컴퓨터가 여러 태스크를 동시에 실행할 수 있는 메커니즘이다. 그러나 이들은 여러 가지 면에서 다르다.
- 생성과 파괴: 일반적으로 새 스레드를 생성하는 것이 새 프로세스를 생성하는 것보다 더 빠르고 더 적은 리소스를 필요로 한다. 반면에, 프로세스를 파괴하는 것은 보통 스레드를 파괴하는 것보다 더 비용이 많이 든다.
- 메모리 관리: 프로세스에는 별도의 메모리 공간이 있는 반면 스레드는 생성된 프로세스의 메모리 공간을 공유한다. 이는 스레드가 동일한 메모리 위치에 있는 데이터에 더 쉽게 액세스하고 수정할 수 있음을 의미하지만, 한 스레드가 다른 스레드의 메모리를 잠재적으로 방해할 수 있음을 의미하기도 한다.
- 통신: 프로세스는 일반적으로 스레드보다 서로 통신하는 데 더 어려움을 겪는다. 스레드는 공유 메모리나 다른 메커니즘을 사용하여 동일한 프로세스 내에서 서로 통신할 수 있는 반면 프로세스는 일반적으로 파이프나 소켓과 같은 더 복잡한 통신 메커니즘을 사용해야 한다.
전반적으로 스레드는 프로그램이 여러 작업을 동시에 수행해야 하고 작업이 리소스를 공유하거나 서로 자주 통신해야 할 때 프로세스보다 일반적으로 선호된다. 프로세스는 일반적으로 태스크가 서로 완전히 독립적이며 리소스를 공유하거나 서로 통신할 필요가 없는 경우에 사용된다.
lock, semaphore, condition variables
참고:
Q. 락, 세마포어, 조건 변수의 차이
락은 동기화 메커니즘으로, 다양한 쓰레드에 의한 공유 자원에 대한 접근을 통제한다. 이는 한번에 한 쓰레드만 자원에 접근할 수 있게 해주며, 그 외 다른 쓰레드가 자원에 접근하려고 하면, 락이 해제될 때까지 block된다.
세마포어는 동기화 메커니즘으로 다양한 쓰레드가 공유 자원에 접근할 수 있게 한다. 하지만 제한된 개수의 쓰레드만 동시에 접근할 수 있다. 세마포어는 쓰레드의 숫자를 나타내는 특정한 값을 가지는데, 이는 동시에 자원에 접근할 수 있는 쓰레드의 개수를 의미한다. 그리고 그 값이 0일 때 자원에 접근하려 하는 쓰레드는 값이 0이 아니게 될 때까지 block된다.
조건 변수는 동기화 메커니즘이다. 조건 변수는 쓰레드로 하여금 특정 조건이 만족될때까지 기다리게 한다. 조건 변수는 보통 락과 연관되어 사용된다. 그리고 쓰레드로 하여금 락을 해제하게 하며, busy waiting 없이 또 다른 쓰레드에 의한 조건 시그널을 받게끔 한다.
락과 세마포어의 가장 중요한 차이는 공유 자원에 대한 접근권을 통제하기 위해 얼마나 세분화되어 있는가의 차이다. 락은 한번에 한 쓰레드만 자원에 접근할 수 있고, 반면 세마포어는 다양한 쓰레드가 동시에 자원에 접근할 수 있게 한다.
또 다른 차이점은 락은 보통 mutual exclusion을 위해 사용된다. 이는 한번에 한 쓰레드만 임계 구역의 코드를 실행할 수 있다는 개념이다. 반면 세마포어는, 다양한 동기화 목적으로 사용될 수 있다. 예를 들어 쓰레드 간의 시그널링이나, resource counting, implementing barriers 같은 것들이 있다.
Q. lock 없이 세마포어만 사용하면 되지 않나?
일반적으로 락 없이 세마포어를 사용하여 여러 스레드에 의한 공유 리소스에 대한 액세스를 동기화할 수 있습니다. 그러나 세마포어를 사용하는 것만으로는 충분하지 않을 수 있으며 프로그램의 올바른 동작을 보장하기 위해 락이 필요할 수 있습니다.
세마포어 외에 락을 사용하는 한 가지 이유는 코드의 중요한 섹션을 한 번에 하나의 스레드만 실행할 수 있는 속성인 상호 배제(mutual exclusion)를 보장하기 위해서이다. 세마포어만으로는 여러 스레드가 동시에 세마포어를 획득하고 임계 섹션을 동시에 실행할 수 있기 때문에 상호 배제를 보장할 수 없다.
세마포어 외에 락을 사용하는 또 다른 이유는 여러 스레드가 공유 데이터에 액세스할 때 발생할 수 있는 경합 조건(race condition)을 방지하기 위해서입니다. 락은 공유 데이터 구조를 동시 액세스 및 수정으로부터 보호할 수 있지만, 세마포어만으로는 이러한 경쟁 조건을 방지하기에 충분하지 않을 수 있다.
요약하면, 세마포어를 단독으로 사용하여 공유 리소스에 대한 액세스를 동기화하는 것이 가능하지만, 세마포어 외에 락을 사용하면 상호 배제 및 경합 조건으로부터의 보호와 같은 추가적인 동기화 보장을 제공할 수 있다.
'크래프톤정글 > PintOS' 카테고리의 다른 글
크래프톤정글 PintOS; Project 3 Diagram (Anonymous Page 까지) (0) | 2023.01.21 |
---|---|
크래프톤정글 PintOS; Project 1, 2 Diagram (0) | 2023.01.21 |
크래프톤정글 9-10주차; WIL - PintOS Project 3 Virtual Memory (0) | 2023.01.21 |
크래프톤정글 8주차; WIL - PintOS Project 2 User Program (1) | 2023.01.21 |