Aesthetic Algorithm
[혼공학습단] Week 5: 프로세스 동기화, 교착 상태 본문
🟪 이번 주 범위 🟪
Chapter 12. 프로세스 동기화
12-1. 동기화란
12-2. 동기화 기법
Chapter 13. 교착 상태
13-1. 교착 상태란
13-2. 교착 상태 해결 방법
Chapter 12. 프로세스 동기화
12-1. 동기화란
✔️ 동기화란 뭐고, 왜 필요할까?
✔️ 프로세스를 동기화하지 않을 경우 어떤 문제들이 발생할까?
멀티프로세스 환경에서는, 여러 프로세스가 동시에 자원(메모리, 파일, 입출력 장치 등)에 접근할 수 있다. 이때 프로세스들이 아무런 제약 없이 동시에 접근하면 다양한 문제가 생기게 된다.
따라서 자원의 일관성과 실행 순서를 보장하기 위한 동기화(synchronization)이 필요하다.
좀 더 자세히 알아보자.
프로세스 동기화란, 프로세스들 사이의 수행 시기를 맞추는 것을 의미하는데, 크게 2가지를 의미한다.
1️⃣ 실행 순서 제어: 프로세스를 올바른 순서대로 실행하기
2️⃣ 상호 배제: 동시에 접근해서는 안 되는 자원에 하나의 프로세스만 접근하게 하기
1️⃣에 대한 예시부터 살펴보자.
우리가 유튜브에 영상을 올리기 위해, 어도비 같은 편집 툴을 사용하여 영상 클립을 만드는 상황이라고 하자.
우리는 영상 클립을 먼저 렌더링하고, 렌더링이 끝난 후 미리보기를 재생하게 된다. 그런데 렌더링 이전에 재생 버튼을 누르면 당연히 파일이 없다는 오류가 뜰 것이다. 따라서 올바른 프로세스는 렌더링 완료 시점에 재생 모듈이 동작하도록 하는 것이다. 이처럼 한 작업이 종료되어야 다음 작업이 가능한 구조를 보장하는 것이 실행 순서 제어다.
2️⃣에 대한 예시도 살펴보자.
상호 배제는 여러 프로세스에 대해, 한 번에 오직 하나만 공유 자원에 접근하도록 하는 것이다.
우리가 은행에 가서 ATM기기를 이용하는 상황이라고 치자. 만일 부모님은 서울에서 ATM으로 돈을 인출하고, 나는 인천에서 같은 계좌로 돈을 이체할 때, 두 거래는 같은 순간 은행 서버로 요청을 보내는 것이다.이때 서버가 동기화 없이 처리하면 잔액이 꼬일 수 있다.이처럼 동시에 접근해서는 안 되는 자원에 동시에 접근하지 못하게 하는 것이 상호 배제를 위한 동기화다.
상호 배제를 위한 동기화 중 생산자와 소비자 문제가 있다.
✅ 생산자와 소비자 문제 (Producer-Consumer Problem)
생산자는 물건을 계속하여 생산하는 프로세스이고, 소비자는 물건을 계속해서 소비하는 프로세스이다.
생산자 프로세스는 버퍼에 데이터를 넣고 소비자 프로세스는 버퍼에서 데이터를 꺼내는 상황을 생각해 보자.
이때, 소비자가 먼저 실행되어 버퍼를 읽으려고 하면 데이터가 없을 수 있다. 따라서 상호 배제를 위한 동기화로, 한 번에
생산자와 소비자가 동시에 버퍼를 수정하지 않도록 한다.
코드 예시로 살펴보자.
저자분의 깃허브 코드를 따 왔고, 코드 해석은 GPT의 도움을 받았다.
#include <iostream> // 입출력 라이브러리
#include <queue> // 큐 자료구조
#include <thread> // 스레드 라이브러리
void produce(); // 생산자 함수 선언
void consume(); // 소비자 함수 선언
// std::queue<int> q; // 원래 큐를 쓸 수도 있지만, 지금은 주석 처리
int sum = 0; // 공유 자원 (전역 변수)
int main() {
std::cout << "초기 합계: " << sum << std::endl;
// producer 스레드 시작 (produce 함수 실행)
std::thread producer(produce);
// consumer 스레드 시작 (consume 함수 실행)
std::thread consumer(consume);
// 두 스레드가 끝날 때까지 대기
producer.join();
consumer.join();
std::cout << "producer, consumer 스레드 실행 이후 합계: " << sum << std::endl;
return 0;
}
즉 프로그램을 시작할 때 sum은 0으로 하고, 두 개의 스레드를 만들어 동시에 실행한다.
producer은 sum을 1씩 증가시키고, consumer은 sum을 1씩 감소시킨다.
모든 스레드가 끝난 뒤 sum값을 출력하게 된다.문제는 공유 변수인 sum을 두 스레드가 동시에 접근해서 수정하다보면 값이 꼬일 수 있다는 것이다.최종 sum의 값이 0이 아닌 상황을, 동기화 없이 공유 변수 접근 시 발생하는 경쟁 상태라고 한다.
✅ 공유 자원(shared resource)과 임계 구역(critical section)
위의 상황에서 총합이라는 공동의 자원을 두고 작업을 하였는데, 이러한 자원을 공유 자원이라고 한다.즉, 여러 프로세스나 스레드가 공동으로 접근 및 사용하는 자원이며, 전역 변수, 파일(동시에 읽고 쓸 수 있음), 입출력장치(프린터)가 될 수도 있다.
이렇게 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역을 임계 구역이라고 한다.만약 여러 프로세스가 동시에 임계 구역의 코드를 실행하게 되는 경우를 레이스 컨디션(race condition)이 발생한다.이러한 경우는 실행 결과가 실행 순서에 따라 달라지게 되는데, 실행할 때마다 값이 달라질 수 있다.
따라서 OS는 임계 구역 문제를 해결하기 위한 3가지 원칙을 지킨다. 1️⃣ 상호 배제(mutual exclusion): 한 프로세스가 임계 구역에 진입했다면 다른 프로세스는 임계 구역에 들어올 수 없다.한 번에 하나씩 접근하도록 잠금(lock)이 필요하다. 위에서 설명했던 은행 계좌 잔액 예시를 떠올리면 된다.
2️⃣ 진행(progress): 임계 구역에 어떤 프로세스도 진입하지 않았다면 임계 구역에 진입하고자 하는 프로세스는 들어갈 수 있어야 한다.
임계 구역이 비어있음에도 대기를 하는 것은 비효율적이기 때문이다. 프린터를 이용하고 싶은 사람이 여러 명인데, 프린터가 놀고 있으면 안되는 것과 마찬가지다.
3️⃣ 유한 대기(bounded waiting): 한 프로세스가 임계 구역에 진입하고 싶다면 그 프로세스는 언젠가는 임계 구역에 들어올 수 있어야 한다.
특정 프로세스가 계속 대기만 한다면 기아 현상이 발생하므로, 대기 횟수나 시간에 제한을 두어야 한다.
12-2. 동기화 기법
✔️ 뮤텍스 락
✔️ 세마포
✔️ 모니터
임계 구역에 오직 1개의 프로세스만 진입하게 하고, 올바른 실행 순서를 보장하기 위한 프로세스 동기화는 어떻게 이루어질까? 동기화를 위한 도구 세 가지를 알아보자.
✅ 뮤텍스 락(Mutex lock: MUTual EXclusion lock)
뮤텍스 락의 개념에 대해 알아보자. 뮤텍스 락이란, 상호 배제를 위한 동기화 도구이다.
즉, 한 번에 하나의 실행 단위만 임계 구역에 들어갈 수 있게 한다.
마치 자물쇠라고 생각하면 된다. 잠금과 해제 두 가지 상태만 가지며, 잠금을 건 스레드만 해제 가능하다.
뮤텍스 락의 구현을 여러 함수와 함께 살펴보기 위한 예제를 준비했다:
#include <stdio.h>
#include <pthread.h>
int sum = 0; // 공유 자원
pthread_mutex_t lock; // 뮤텍스(잠금 장치)
void acquire() { // 잠금 함수
pthread_mutex_lock(&lock);
}
void release() { // 잠금 해제 함수
pthread_mutex_unlock(&lock);
}
void* producer(void* arg) { // 생산자: sum을 1씩 증가
for (int i = 0; i < 5; i++) {
acquire(); // 임계 구역 잠금
sum++;
printf("생산자: sum = %d\n", sum);
release(); // 잠금 해제
}
return NULL;
}
void* consumer(void* arg) { // 소비자: sum을 1씩 감소
for (int i = 0; i < 5; i++) {
acquire(); // 임계 구역 잠금
sum--;
printf("소비자: sum = %d\n", sum);
release(); // 잠금 해제
}
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_mutex_init(&lock, NULL); // 뮤텍스 초기화
pthread_create(&t1, NULL, producer, NULL); // 생산자 스레드 시작
pthread_create(&t2, NULL, consumer, NULL); // 소비자 스레드 시작
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_mutex_destroy(&lock); // 뮤텍스 제거
return 0;
}
함수를 기준으로 살펴보자.
acquire()은 뮤텍스를 잠금하는 역할을, release()는 뮤텍스 잠금을 해제하는 역햘을 한다.
main()에서는 뮤텍스를 초기화하고, producer과 consumer 스레드를 각각 실행하고, 두 스레드가 모두 종료될 때까지 대기한 후, 실행이 끝나면 뮤텍스를 제거한다.
✅세마포(semaphore)
우리가 무신사에 가서 옷을 착용하는 상황을 생각해보자. 피팅룸(공유 자원)은 여러 개가 있듯이 여러 사람(여러 프로세스)가 각각 피팅룸에 접근이 가능해야 한다. 이처럼 공유 자원이 여러 개 있는 상황에서도 적용이 가능한 동기화 도구가 세마포다.
피팅룸에 ON이 켜져 있으면 맨 앞에 대기하던 사람은 들어갈 수 없다. (1명씩 들어가야 하기 때문에 임계 구역과도 같다.)
하지만 피팅하던 사람이 나오고 OFF가 되면, 피팅룸 점원이 대기열에 있는 사람에게 가서 알려주고 입장을 시킨다. 이처럼 우리가 ON/OFF 신호를 통해 피팅룸에 들어갈 수 있냐, 없냐의 신호를 받을 수 있다.
세미포 개념을 표현하면, 이용 가능한 피팅룸 개수가 S, S=0이면 wait을 호출해 대기하고, 방이 비었을 땐 S=S+1니까 빈 방이 났음을 알리는 signal을 호출해 대기 중인 사람을 입장시킨다.
세마포는 동시에 접근 가능한 실행 단위(스레드 및 프로세스)의 개수를 제어하며, 정수값을 이용한다.
카운팅 세마포는 0이상 N까지, 즉 N개까지 동시 접근을 허용한다.연산에 대해 간단히 알아보고 예제 코드를 살펴보자.
전역 변수 S: 임계 구역에 진입할 수 있는 프로세스의 개수를 나타낸다.
wait(): 임계 구역에 들어가도 좋은지, 기다려야 할지를 알려준다.
signal(): 임계 구역 앞에서 기다리는 프로세스에 가도 좋다는 신호를 준다.
int S = 2; // 세마포 값: 동시에 2개 스레드만 허용
pthread_mutex_t lock;
pthread_cond_t cond;
void wait_semaphore() { // wait 연산 (P 연산)
pthread_mutex_lock(&lock);
while (S <= 0) { // 세마포 값이 0 이하이면 대기
pthread_cond_wait(&cond, &lock);
}
S--; // 자원 사용 시작 → 세마포 값 감소
pthread_mutex_unlock(&lock);
}
void signal_semaphore() { // signal 연산 (V 연산)
pthread_mutex_lock(&lock);
S++; // 자원 사용 종료 → 세마포 값 증가
pthread_cond_signal(&cond); // 대기 중인 스레드 깨움
pthread_mutex_unlock(&lock);
}
void* worker(void* arg) {
wait_semaphore(); // 세마포 획득
printf("작업 시작: %ld\n", (long)arg);
sleep(1); // 작업 중
printf("작업 종료: %ld\n", (long)arg);
signal_semaphore(); // 세마포 반환
return NULL;
}
int main() {
pthread_t threads[5];
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
// 5개의 스레드 생성
for (long i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL, worker, (void*)i);
}
// 모든 스레드 종료 대기
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
카운팅 세마포가 어떻게 동작하는지 알아보자. 세마포는 동시에 접근 가능한 자원의 개수를 관리하는 변수임을 잊지 말자.S 변수는 현재 사용 가능한 자원의 개수이다. S=2라면, 동시에 2개의 스레드만 작업을 진행할 수 있다는 의미이다.wait()은, S가 0 이하라면 자리가 날 때까지 기다리고, 자리가 생기면 S--를 하여 자원 개수를 줄인다.signal()은, 자원 사용이 끝난 후 호출하며, S++해서 자원을 하나 반환하여 다른 스레드에게 자리가 생겼다는 시그널을 보내는 역할을 한다.
✅ 모니터(moniter)
모니터는 스레드보다 편리한 도구로, 동기화 추상화 도구이다. (OOP 개념이 살짝 들어간다.)
공유 자원과 해당 자원을 접근하는 함수(메서드)를 하나의 객체로 묶어, 한 번에 하나의 스레드만 모니터 내부의 함수(메서드) 실행을 허용한다. 모니터 내부에는 공유 데이터 영역, 데이터를 조작하는 메서드, 조건 변수가 포함된다. 스레드가 모니터에 진입하면 자동적으로 상호 배제가 적용된다.
조건 변수는 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수이며, wait()과 signal() 연산을 통해 스레드 간 협력을 가능하게 한다.
wait(): 호출한 프로세스의 상태를 대기 상태로 전환한 후, 일시적으로 조건 변수에 대한 대기 큐에 삽입한다.
signal(): 대기 중인 스레드 하나를 깨워서 실행을 재개시킨다.
Entry Queue는 문 앞의 대기열이라고 생각하자. 모니터 내부에 진입하기 위해 대기 중인 스레드 목록이다.
맨 앞 스레드가 진입하면 자동으로 잠금이 걸려, 다른 스레드는 들어오지 못한다.
모니터에서는 한 번에 하나의 스레드만 실행 가능하므로, first-in-first-out 방식이 일반적이다.
Shared Data는 여러 스레드가 함께 사용해야 하는 데이터가 위치하는 영역으로, 동시에 한 스레드만 접근 가능하다.
Operation 영역에서는 자동 상호 배제를 적용받으며, 스레드가 wait()상태로 이동하거나 signal()로 깨어난다.
Initialization Code는 모니터 객체가 처음 생성될 때 실행되는 초기화 절차를 나타낸다.
스레드가 모니터 내부 함수 실행을 종료하면 자동적으로 잠금 해제가 되어, Entry Queue에 대기 중인 다음 스레드가 진입하게 된다.
Chapter 13. 교착 상태
13-1. 교착 상태란
✔️ 교착 상태가 뭘까?
✔️ 교착 상태를 표현하는 자원 할당 그래프와 교착 상태의 발생 원인이 뭘까?
단어를 듣기만 해도 머리가 지끈거리는 교착 상태.
실생활에서도 교통 체증이 심하면 굉장히 스트레스를 받게 된다. 컴퓨터에서도 교착 상태가 발생하는데, 그 개념과 발생 원인에 대해 알아보자.
개인적으로 PyCharm을 이용하며 병목 현상 때문에 열받았던 적이 있는데, 그것과는 다른 개념이라고 한다.
교착 상태는 한 번 발생하면 외부 개입이 있지 않는 이상은 스스로 풀리지 않으며, 병목 현상은 속도는 느려지지만 완전 멈춰버리진 않는다고 한다. 어떤 작업이 시간이 오래 걸려서 속도가 느려지는 현상이라고 함.
✅ 교착 상태(Deadlock)
두 개 이상의 프로세스나 스레드가 서로가 가진 자원을 기다리며, 진행이 멈춰 버리는 현상이다.
흔들다리 위를 생각해보자. 좁은 흔들다리 위해서, 두 사람이 서로 양보하지 않고 버티다가(니가 비켜야지 내가 가지-)
둘 다 영원히 길을 못 건너는 상황이다.
코드로 잠시 보자:
### 프로세스 A ###
lock1 = true;
while (lock2 == true)
;
// 임계 구역 작업
lock1 = false;
### 프로세스 B ###
lock2 = true;
while (lock1 == true)
;
// 임계 구역 작업
lock2 = false;
A는 lock2가 false가 되길 바라고, B는 lock1이 false가 되길 바란다면 교착 상태가 발생하게 되겠다.
좀 감성적인 비유지만 이건 어떨까?서로 좋아하는 한 소년과 소녀가 있는데, 소년은 "누굴 좋아하는지 네가 먼저 말하면 나도 누굴 좋아하는지 말하겠다"고 하고, 소녀도 마찬가지로 소년의 마음을 먼저 알고 싶어 한다. 그러나 둘 다 먼저 말 할 생각이 없다면 이 둘의 관계도 교착 상태에 빠져 영원히 서로의 마음을 확인하지 못하는 것이다. 안타깝다.
여기에서 프로세스는 소년과 소녀, 마음 고백은 자원이 되겠다.
✅ 자원 할당 그래프(resource-allocation graph)
어떤 프로세스가 어떤 자원을 사용하는지를 표현하는 그래프다.
몇 가지 규칙이 있다:
1️⃣ 프로세스는 원으로, 자원의 종류는 사각형으로 표현한다.
2️⃣ 사용할 수 있는 자원의 개수는 자원 사격형 내에 점으로 표현한다.
3️⃣ 프로세스가 어떤 자원을 할당받아 사용 중이라면, 자원에서 프로세스를 향해 화살표를 표시한다.
4️⃣ 프로세스가 어떤 자원을 기다리고 있다면 프로세스에서 자원으로 화살표를 표시한다.
위 그림을 보면, P1 -> R1의 경우 프로세스 P1이 자원 R1을 요청하고 있다. P1 <- R2의 경우 자원 R2가 P1에 1개 할당되어 있다.
교착 상태가 발생하는 원인은 뭘까? 4가지를 살펴보자.
✅ 상호 배제(mutual exclusion): 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없을 때
✅ 점유와 대기(hold and wait): 자원을 할당받은 상태에서 다른 자원을 할당받기를 기다리는 상태
✅ 비선점(nonpreemptive): 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못 하는 상태
✅ 원형 대기(circular wait): 프로세스들이 원의 형태로 자원을 대기하는 것
13-2. 교착 상태 해결 방법
✔️ OS가 교착 상태를 회피/예방/검출 및 회복하는 방법은?
교착 상태 예방은, 앞서 얘기한 교착 상태 발생 조건 4가지중 하나를 충족하지 못하게 하는 것과 같다.
상호 배제를 없앤다는 것은, 모든 자원을 공유 가능하게 만드는 것이다. 그러나, 이는 현실적으로 어려운 방식이다.
점유와 대기를 없앤다는 것은, 특정 프로세스에 자원을 몰빵하거나 아예 주지 않는 all or nothing이다. 그러나, 이는 자원의 활용률이 낮아지는 단점이 있다.
비선점 조건을 없앤다는 것은, 이용 중인 프로세스로부터 자원을 뺏을 수 있다는 것이다. 그러나 이를 모든 상황에 적용하기엔 무리가 있다. (프린터로 누군가 인쇄 중인데 그걸 중단하고 다른 걸 인쇄할 수는 없지 않은가.)
원형 대기 조건을 없앤다는 것은, 모든 자원에 번호를 붙이고 오름차순으로 자원을 할당하는 방식이다. 그러나 시스템 안의 모든 자원에 넘버링을 하는 것과 어떤 번호를 붙여야 하는지에 따라 복잡한 상황이 발생한다.
✅ 교착 상태 회피
교착 상태가 발생하지 않을 정도로만 자원을 할당하는 방식이다. (찔끔 찔끔)
프로세스들에 할당할 수 있는 자원이 적은데, 모든 프로세스들이 많은 자원을 요구하는 상황에서 교착 상태가 발생할 가능성이 크기 때문이다.
✔️ 안전 상태(safe state): 교착 상태가 발생하지 않고 모든 프로세스가 정상적으로 자원을 할당받고 종료될 수 있는 상태
✔️ 불안전 상태(unsafe state): 교착 상태가 발생할 수도 있는 상황
✔️ 안전 순서열(safe sequence): 교착 상태 없이 프로세스들에 자원을 할당할 수 있는 순서
프로세스와 스레드가 자원을 사용하기 위해서는 1) OS에 자원 요청 2) OS로부터 자원 할당받음 3) 자원 반환의 단계가 필요하다. 은행 대출 예시를 통해 자세히 알아보자:은행에 10억 현금(자원)이 있다고 치자. 3명의 고객(프로세스) P1, P2, P3가 서로 다른 스타트업 운영을 위해 돈을 빌리는 상황이다. 각 고객은 얼마가 필요한지 최대 요구량을 은행에 알린다. 현재 얼마를 빌렸는지(할당량), 앞으로 더 필요한 금액(잔여 요청량)이 있다.여기서 안전 상태란, 모든 고객이 대출금을 안전하게 받고 스타트업 운영을 할 수 있는 상황이다.P1이 2억, P2가 3억, P3이 4억이 필요하다면 P1-P2-P3 순서로 빌려주면 모두가 성공적으로 대출을 받을 수 있다.안전 순서열이 바로 이 순서가 되겠다.불안전 상태란, 현재 교착 상태는 아니지만 잘못하면 교착 상태로 갈 수도 있는 상황이다.P1이 11억이 필요하다고 하면, P1은 1억이 모자라고 은행도 현금이 없어 다른 고객들마저 대기 상태에 빠지는 상황이다.
교착 상태를 검출한 뒤 회복하는 방식은 어떤 걸까?OS는 자원이 필요한 프로세스에 그때그때 할당을 하고, 교착 상태 여부를 주기적으로 검사한다. 회복하는 방식은 다음과 같다:
✅ 선점을 통한 회복: 교착 상태가 해결될 때까지 한 프로세스씩 자원을 몰아주는 방식
✅ 프로세스 강제 종료를 통한 회복: 교착 상태에 놓인 프로세스를 모두 강제 종료하거나, 한 프로세스씩 강제 종료할 수 있다. 예를 들어 게임 서버를 생각해보자. P1, P2, P3가 서로의 세션 락을 점유하며 기다리는 데드락 상태에서, 서버 관리자가 연루된 모든 P1~P3 세션을 종료하고 세션 락을 반환하여 게임 재접속을 유도하는 상황이다. 이때 빠른 해결이 된다는 점에서는 좋지만 모든 작업을 손실하게 된다는 단점도 있다.
혹은 가장 진행률이 낮고 점유 자원 수가 적은 프로세스부터 순차적으로 종료하는 방식은, 손실을 최소화할 수 있으나 여러 번의 종료가 필요할 수 있다. (완전히 해소될 때까지 시간이 걸림)
✅이번 주 숙제
1. 363p, 뮤텍스 락과 세마포에 대한 설명으로 옳지 않은 것은?
1) 뮤텍스 락은 임계 구역을 잠근 뒤 임계 구역에 진입함으로써 상호 배제를 위한 동기화를 이룹니다. ⭕
2) 세마포는 공유 자원이 여러 개 있는 상황에서도 이용할 수 있습니다. ⭕ (카운팅 세미포!)
3) 세마포를 이용해 프로세스 실행 순서 제어를 위한 동기화도 이룰 수 있습니다. ⭕ (실행 순서 제어도 가능하다.)
4) 세마포를 이용하면 반드시 바쁜 대기를 해야 합니다. ❌ (아까 사용한 비유를 적용하자면.. 바쁜 대기 방식이라면 피팅룸 앞에 있는 사람이 계속 비었나? 확인해야 한다. 그 동안 계속 CPU를 사용하는 방식이다. 그러나 세미포를 사용하면 바쁜 대기 없이 딴 일 하고 있다가 피팅룸 점원이 와서 빈 방 났다고 알려주면 되기 때문에 기다리는 동안 CPU를 안 써도 된다.)
'Computer Science > 컴퓨터구조&운영체제' 카테고리의 다른 글
[혼공학습단] 회고 (6) | 2025.08.24 |
---|---|
[혼공학습단] Week 6: 가상 메모리, 파일 시스템혼공학습단] Week 6: 가상 메모리, 파일 시스템 (2) | 2025.08.24 |
[혼공학습단] Week 4: 운영체제, 프로세스와 스레드, CPU스케줄링 (11) | 2025.07.30 |
[혼공학습단] Week 3 메모리와 보조기억장치, 입출력장치 (8) | 2025.07.30 |
[혼공학습단] Week 2: CPU의 작동원리와 성능 향상 기법 (3) | 2025.07.18 |