세종대학교 - 운영체제 및 보안 수업
Process Concept
- 프로세스 개념
- 프로세스 스케쥴링
- 프로세스 작동
- 프로세스 간 통신
- IPC 시스템 예시
- Communication in Client-Server Systems
Objectives
- 프로세스의 개념 소개
- 모든 계산의 기초가 되는 형식의 실행에 있는 프로그램
- 다양한 형태의 프로세스들을 묘사
- 스케쥴링, 생성과 종료, 소통 방식을 포함
- 공유 메모리와 메시지 전달을 이용하는 내부 프로세스 커뮤니케이션을 탐험
- client-server 시스템의 소통방식을 묘사
프로세스 개념 (3.1.)
- 운영체제는 다양한 프로그램을 실행시킴
- batch 시스템
- jobs (=process)
- Time-shared 시스템
- 사용자 프로그램 또는 수행업무
- batch 시스템
- 교과서는 job과 process를 거의 같은 용어로 사용
- 프로세스
- 실행 중인 프로그램
- 프로세스 실행은 순차적으로 진행되어야함
- 다양한 부분
- 프로그램 코드, text section으로 불림
- program counter (현재 활동을 포함한), program registers
- stack (일시적인 데이터를 포함한)
- 함수 파라미터, 리턴 주소, 지역변수 등
- Data section (전역 변수 포함한)
- Heap (실행 중 동적으로 할당된 메모리를 포함한)
- 프로그램은 수동적 실체 (디스크에 저장되어있는) (실행가능한 파일로), 프로세스는 능동적
- 프로그램은 실행가능한 파일이 메모리에 로드될 때 프로세스가 됨
- 하나의 프로그램은 여러 프로세스들이 될 수 있음
- 같은 프로그램도 다수의 사용자가 사용하는 것을 고려
메모리 안 프로세스 (그림 3.1)
프로세스 상태 (3.1.2.)
- 프로세스가 실행될 때, 상태가 바뀜
- new : 프로세스가 생성됨
- running : 명령이 실행됨
- waiting : 프로세스가 어떤 이벤트가 발생하는 것을 기다림
- (사용자 동작 기다림)
- ready : 프로세스가 프로세서에 할당되는 것을 기다림
- (CPU 동작 기다림)
- terminated : 프로세스가 실행을 끝냄
프로세스 상태 다이어그램 (그림 3.2)
Process Control Block (PCB), 프로세스 제어 블럭 (3.1.3.)
- 각각의 프로세스와 관련된 정보, task control block 이라고도 불림
- (각 프로세스 별 각각의 PCB 존재)
- Process state
- running, waiting, etc
- Program counter
- 다음에 실행될 명령의 위치
- CPU resgister
- 모든 프로세스 중심 레지스터의 내용
- CPU scheduling 정보
- 우선순위, 큐 포인터 스케쥴링
- 메모리 관리 정보
- 프로세스에 할당된 메모리
- Accounting 회계,기록 같은 느낌) 정보
- CPU 사용량, 시작 후 클락 타임, 시간 제한
- 입출력 상태 정보
- 프로세스에 할당된 입출력 장치, 열려 있는 파일들의 리스트
프로세스 간 CPU Switch (그림 3.6)
Threads (3.1.4.)
- 지금까지, 프로세스는 하나의 실행 스레드를 가졌음
- 각 프로세스 별 다양한 프로그램 카운터를 가지는 것을 고려
- 다수의 위치 한번에 실행 될 수 있음
- 다수의 제어 스레드 -> threads
- 다수의 위치 한번에 실행 될 수 있음
- PCB 안에 스레드 정보들과 다수의 프로그램 카운터를 위한 저장공간이 있어야함
- 다음 챕터에서 공부
리눅스 프로세스 표현
task_struct
pid t pid; /* process identifier */
long state; /* state of the process */
unsigned int time slice /* scheduling information */
struct task struct *parent; /* this process’s parent */
struct list head children; /* this process’s children */
struct files struct *files; /* list of open files */
struct mm struct *mm; /* address space of this process*/
프로세스 스케쥴링 (3.2)
- CPU 사용을 최대화, time sharing을 위해 CPU 안의 프로세스 변환을 빠르게
- 프로세스 스케쥴러는 CPU에 다음 실행을 위한 사용 가능한 프로세스 중에 선출
- (자원 한정 -> but 여러 프로세스 사용 -> scheduler 필요)
- 프로세스의 스케쥴링 큐를 유지
- Job queue
- 시스템 안의 모든 프로세스 설정
- Ready queue
- 메인 메모리에 있는 실행을 ready 또는 waiting 하는 모든 프로세스를 설정
- Device queues
- 입출력장치를 위해 기다리는 프로세스들을 설정
- 프로세스는 다양한 큐 중 속에서 이주.
- Job queue
Ready queue와 다양한 입출력 장치 queues (그림 3.4)
프로세스 스케쥴링 표현 (그림 3.5)
큐 다이어그램 (큐, 리소스, 흐름 표현)
프로세스가 CPU에 할당되고 실행되면 여러 이벤트 중 하나가 발생할 수 있음
- 프로세스는 I/O 요청을 발행할 수 있고, 그 뒤에 I/O 큐에 위치시킬 수 있음
프로세스는 새로운 자식 프로세스를 만들 수 있고 자식의 종료될때까지 기다림
프로세스는 CPU로부터 강제로 제거될 수 있고, (인터럽트의 결과로서), 그게 ready queue에 저장됨
스케쥴러
- Long-term scheduler (job scheduler)
- ready queue에서 어떤 프로세스를 가지고 와야하는지 선택
- (순서 관리 느낌)
- 새로 불러올 때
- Short-term scheduler (CPU scheduler)
- 어떤 프로세스가 다음에 실행되어야하고, CPU에 할당되는지 선택
- (바로 직전 친구 관리)
- 다시 끝나고 돌아갈 때
- Short-term scheduler는 자주 부름 (milli 초) => 빨라야함
- Long-term scheduler는 자주 부르지는 않음 (초, 분 단위) => 느려도 됨
- multiprogramming의 정도를 long-term scheduler과 관리
- (short-term이 힘들어 보이면 long-term이 관리)
- 프로세스 두 가지
- I/O-bound 프로세스
- 계산보다 I/O를 수행하는데 더 많은 시간 사용
- 많고 짧은 CPU burst(~만 연속적으로 사용하는 것)
- CPU-bound 프로세스
- 계산에 더 많은 시간 사용
- 적은 긴 CPU burst
- (당연히 cpu-bound 프로세스는 cpu를 많이 쓰니깐 적은 빈도로 쭉 길게 cpu burst가 일어나겠지?)
- I/O-bound 프로세스
- long-term scheduler는 프로세스 믹스를 좋게 노력
- (프로세스 믹스를 어떻게 해야 효율적으로 cpu가 작동할 수 있을지를 말하는 듯)
추가적으로 Medium Term Scheduling
medium-term scheduler
다수의 프로그래밍의 정도를 감소하는 것이 필요할때 추가될 수 있음
메모리에서 프로세스를 지우고, 디스크에 저장후, 나중에 실행을 계속할때 디스크로부터 가져옴(swapping)
모바일 시스템의 멀티테스킹
- 몇몇 또는 이전 시스템은 프로세스가 작동할 땐 다른 것들은 일시정지되었음
- 화면 공간으로 인해 사용자 인터페이스 제한 iOS는
- 단일 foreground 프로세스
- UI를 통해 제어됨
- 다중 background 프로세스
- 메모리에 있고, 실행중이고, 화면에는 없고, 제한 있음
- 제한에는 단일, 짧은 작업, 이벤트 알림 수시느 오디오 재생과 같은 특정 장기 실행 작업 포함
- 단일 foreground 프로세스
- 안드로이드는 제한 거의 없이 포그라운드,백그라운드에서 작동
- 백그라운드 프로세스는 작업을 수행하는 서비스 사용
- 백그라운드 프로세스가 멈추지 않는 한 서비스 계속 동작
- 서비스는 사용자 인터페이스 없이, 작은 메모리만 사용
문맥 교환 (3.2.3.)
- 다른 프로세스로 CPU 스위치가 발생할 때, 시스템은 이전 프로세스의 상태를 반드시 저장해야하고, context switch에 의해 새로운 프로세스를 위한 저장된 상태를 로드해야함
- 프로세스의 context는 PCB에 표현됨
- Context-switch 시간은 오버헤드
- 시스템은 바뀌는 동안 활용적인 작업을 할 수 없음
- OS와 PCB가 복잡할수록 context switch가 더 오래걸림
- 시간은 하드웨어 지원에 달림
- CPU당 다중 레지스터를 지원해서 -> 한번에 다수의 context가 로드됨
프로세스에 대한 연산 (3.3.)
- 시스템은 매커니즘을 제공
- 프로세스 생성
- 종료
- 세부적인 사항
프로세스 생성 (3.3.1.)
부모 프로세스는 자식 프로세스들을 생성하고 그것들은 다른 프로세스들을 생성함
- (자식 프로세스는 부모 프로세스에서 필요한거, 근데 자기가 안 하는거)
- 프로세스 트리를 형성
- (트리구조로 만들어짐, children이 여러 개 생성되기 때문)
일반적으로, 프로세스는 process identifier(pid)에 의해 식별하고 관리
공유 리소스 옵션에 의한 분류 (os 상황에 따라 설정)
- 부모 자식 간 모든 리소스를 공유
- 자식은 부모 리소스의 부분집합을 공유
- 부모 자식 간 리소스 공유 안함
실행에 의한 분류
- 부모 자식은 동시에 실행
- 부모는 자식이 종료될 때까지 기다림
주소 공간
- 자식이 부모과 중복
- 자식이 프로그램을 로드함
unix example
fork()
- 새로운 프로세스를 만드는 시스템 콜
exec()
fork() 이후에 프로세스의 메모리 공간을 새로운 프로그램으로 대체하는 시스템 콜
리눅스 프로세스 트리
유닉스와 리눅스 시스템에서, ps 명령어로 프로세스 리스트를 얻을 수 있음
ex)
ps -el
나눠진 프로세스를 forking하는 c 프로그램
- unix의 fork() 시스템 콜 사용 → (과제2 1번 문제)
윈도우 api에 의해 생성하는 것도 똑같음
프로세스 종료 (3.3.2.)
프로세스는 마지막 요소를 실행하고 os에 지울것을 요청 (exit())
- 자식에서 부모로 결과 데이터 (wait()에 의해)
- 프로세스의 리소스는 os에 의해 해제
부모는 자식 프로세스의 실행을 종료 (abort())
- (자식 프로세스가 리소스를 많이쓰거나, 정상 진행 안하면 abort())
- 자식이 할당된 리소스를 초과 사용하면
- 자식에게 할당된 작업이 요구되지 않ㅇ르 때
- 부모가 종료될때
- 몇몇 os는 부모가 종료되도 자식이 계속되는 것을 허용하지 않음
- 모든 자식 종료
- 계단식 종료 (아까 트리구조였으니깐)
- 모든 자식 종료
- 몇몇 os는 부모가 종료되도 자식이 계속되는 것을 허용하지 않음
종료를 위해 기다릴때, pid 반환
pid t pid; int status; pid = wait($status);
프로세스가 종료됐는데, 부모가 wait() 안 하면 좀비 프로세스됨
부모가 종료되면, 프로세스는 orphans(고아)
다중프로세스 아키텍쳐 - 크롬 브라우저
- 많은 웹 브라우저가 단일 프로세스로 작동 (아직도 그런애 있음)
- 한 웹사이트가 문제 생기면, 전체 브라우저가 문제 생김
- 구글 크롬 브라우저는 3가지 카테고리를 가진 멀티프로세스 (탭 기능 -> 다 자식 프로세스)
- browser 프로세스
- UI, 디스크, I/O 네트워크 관리
- renderer 프로세스
- 각 웹사이트가 새롭게 열리면 웹페이즈를 렌더링 하고, html,js를 다룸
- 샌드박스에서 작동, 디스크와 I/O네트워크를 제한하는, 보안 유출 효과를 최소화
- plug-in 프로세스
- 각 플러그인 형식을 위함
- browser 프로세스
프로세스 간 통신 (3.4.)
시스템에 있는 프로세스들은 독립적이거나 협동함
협동하는 프로세스는 다른 프로세스에 공유데이터를 포함해서 영향을 주거나 받을 수 있음
- 독립 프로세스는 반대
협동 프로세스의 이유
- 정보 공유
- 계산 속도 향상
- 모듈성
- 편리성
협동 프로세스는 interprocess communication (IPC)가 필요
IPC 두가지 모델
공유 메모리 (b)
메시지 전달 (a)
프로세스 간 통신 방식 - 공유 메모리 (3.5.)
생산자-소비자 문제
- 협동 프로세스의 패러다임에서, 생산자 프로세서는 소비자 프로세스가 소비하는 정보를 생산함
- unbounded-buffer
- 버퍼의 실질적인 제한 없음
- bounded-buffer
- 고정된 버퍼 사이즈 사용
- unbounded-buffer
bounded-buffer - 공유메모리 해결
공유 데이터
#define BUFFER_SIZE 10 /* *(사이즈 제한)* */ typedef struct { . . . } item; item buffer[BUFFER_SIZE]; int in = 0; /* *(생산자 추가하면 증가)* */ int out = 0; /* *(소비자 추가하면 증가)* */
- 정확한 해결책이지만 , buffer 크기보다 하나 작은 요소밖에 사용 안됨
- (in,out buffer_size만큼 차면 다시 앞으로 가서 사용할건데 out이랑 in 같아질 때까지 기다려야 해서)
bounded-buffer - producer
item next produced;
while (true) {
/* produce an item in next produced */
while (((in + 1) % BUFFER SIZE) == out); /* do nothing */
buffer[in] = next produced;
in = (in + 1) % BUFFER SIZE;
}
bounded-buffer - consumer
item next consumed;
while (true) {
while (in == out); /* do nothing */
next consumed = buffer[out];
out = (out + 1) % BUFFER SIZE;
/* consume the item in next consumed */
}
프로세스 간 통신 방식 - 메시지 전달 (3.6.)
- 프로세스가 소통하고 행동을 동기화하기 위한 방식
- 메시지 시스템
- 프로세스는 공유된 변수의 의존 없이 서로 소통함
- IPC 요소가 제공하는 두가지 방식
- send(message)
- 메시지 크기가 고정되거나 변형가능
- receive(message)
- send(message)
- P와 Q가 소통하기 위해서 아래 내용 필요
- comunication link 설립
- send/receive에 의해 메시지 교환
- communication link의 구현
- 물리적 (공유 메모리, 하드웨어 버스(통로))
- 논리 (다이렉튼지, 동기화하는지, 자동적인지 or 명시적 버퍼링인지)
구현 질문
- 어떻게 link를 설계하는지
- 링크가 두 개 이상의 프로세스와 관련시킬 수 있는지
- 프로세스 소통의 쌍 사이에 몇 개의 링크가 있을 수 있는지
- 링크의 능력이 뭔지
- 링크가 수용하는 메시지의 크기를 고정할지, 변환가능하게 할지
- 링크가 간접적으로 갈지, 직접적으로 할지
직접 소통 - Naming (3.6.1.)
- 프로세스는 서로 명시적으로 이름을 지정해야 함
- send (P, message)
- 프로세스 P로 메시지 보내기
- receive(Q, message)
- 프로세스 Q에서 메시지 수신
- send (P, message)
- 통신 링크의 속성
- 링크는 자동으로 설정
- 링크는 정확히 한 쌍의 통신 프로세스와 관련이 있음
- 각 쌍 사이에는 정확히 하나의 링크가 존재
- 링크는 단방향일 수 있지만 일반적으로 양방향
간접 통신 - 메일박스 사용 (3.6.1.)
- 메시지는 사서함(포트라고도 함)에서 전달 및 수신됩니다.
- 각 사서함은 고유한 ID를 가지고 있음
- 프로세스는 사서함을 공유하는 경우에만 통신할 수 있음
- 통신 링크의 속성
- 프로세스가 공통 사서함을 공유하는 경우에만 링크가 설정
- 링크는 많은 프로세스와 연관될 수 있음
- 각 프로세스 쌍은 여러 통신 링크를 공유할 수 있음
- 링크는 단방향 또는 양방향일 수 있음
- 작동
- 새로운 메일박스 생성
- 메일박스 통해 메시지 보내기 및 받기
- 메일박스 삭제
- 프리미티브는 다음과 같이 정의
- send(A, message)
- 사서함 A로 메시지 보내기
- receive(A, message)
- 사서함 A에서 메시지 받기
- send(A, message)
- 메일박스 공유
- P1, P2 및 P3 메일박스 A
- P1, 전송; P2 및 P3 수신
- 그럼 누가 받냐
- 솔루션
- 링크를 최대 두 개의 프로세스와 연결하도록 허용
- 한 번에 하나의 프로세스만 수신 작업을 실행하도록 허용
- 시스템이 수신자를 임의로 선택할 수 있도록 허용. 보낸 사람은 받는 사람이 누구인지 알림
synchronization (3.6.2.)
- 메시지 전달이 차단 또는 차단하지 않는 형식
- 차단은 동기식으로 간주
- (리시버에게 계속 확인)
- 전송 차단은 메시지가 수신될 때까지 발신자가 차단
- 수신 차단은 메시지를 사용할 수 있을 때까지 수신자 차단
- 비차단은 비동기로 간주
- 비차단 전송은 발신자가 메시지를 보내고 진행
- 비차단 수신은 수신자가 유효한 메시지 또는 null을 수신
- 다른 조합도 가능
- 전송과 수신이 둘다 막혀도, 랑데부 가능
- 생산자-소비자는 경제자가 됨
message next produced;
while (true) {
/* produce an item in next produced */
send(next produced);
}
message next consumed;
while (true) {
receive(next consumed);
/* consume the item in next consumed */
}
Buffering (3.6.3.)
- 메시지의 큐는 링크로 접근; 세가지 방법으로 구현됨
- 가능 메시지 개수가 큐 길이라고 생각하면됨
- zero capacity (무용량)
- 0 메시지
- 전송자는 수신자를 무조건 기다림 (랑데부)
- bounded capacity (유한 용량)
- 유한한 메시지 길이
- 전송자는 링크가 다 차면 기다림
- unbounded capacity (무한 용량)
- 무한한 길이
- 전송자는 기다리지 않음
IPC 시스템의 예시 - POSIX (한번읽어보기) (3.7.)
posix 공유 메모리
프로세스는 공유 메모리 영역을 처음 생성
shm_fd = shm_open(name, O CREAT | O RDRW, 0666);
존재하는 영역을 공유하기 위해 열기
객체의 크기를 설정
ftruncate(shm fd, 4096);
프로세스는 이제 공유메모리에 쓰기 가능
sprintf(shared memory, "Writing to shared memory");
IPC 시스템의 예시 - Mach (한번읽어보기) (3.7.2.)
- Mach 통신은 메시지 기반
- 심지어 시스템 호출도 메시지
- 각 작업은 생성 시 두 개의 사서함을 받음
- 커널 및 알림
- 메시지 전송을 위해 필요한 세 개의 시스템 호출
- msg_send(), msg_receive(), msg_rpc()
- port_allocate()를 통해 생성된 통신에 필요한 사서함
- 송수신은 유연. 예를 들어 사서함이 가득 차면 네 가지 옵션 있음
- 무기한 대기
- 최대 n밀리초 대기
- 즉시 반환
- 일시적으로 메시지를 캐시
IPC 시스템 예시 - 윈도우 (3.7.3.)
고급 로컬 프로시저 호출(LPC) 기능을 통한 메시지 전달 중심
- 동일한 시스템의 프로세스 간에만 작동
- 통신 채널을 설정하고 유지하기 위해 포트(예: 사서함)를 사용
- 통신은 다음과 같이 작동
- 클라이언트는 하위 시스템의 연결 포트 개체에 대한 핸들을 엽니다.
- 클라이언트가 연결 요청을 보냄
- 서버는 두 개의 개인 통신 포트를 생성하고 핸들을 클라이언트에게 반환
- 클라이언트와 서버는 해당 포트 핸들을 사용하여 메시지나 콜백을 보내고 응답을 수신
Local Procedure Calls in Windows XP
클라이언트-서버 시스템 소통 방식
- Sockets
- Remote Procedure Calls
- Pipes
- Remote Method Invocation (java)
소켓 (3.8.1.)
소켓은 소통간 엔드포인트로 정의
- (커뮤니케이션 간 양단)
IP 주소와 포트의 연결
- 메시지 패킷 시작에 포함된 숫자
- 호스트의 네트워크 서비스를 차별화하기 위해
소켓의 161.25.19.8:1652 -> 포트가 1652고, 호스트가 161.25.19.8임
소통은 소켓 쌍 사이에 지속됨
1024 아래 포트는 대부분 알려져있음, 기준에 따라
127.0.0.1 (loopback)과 같은 특수 ip, 프로세스가 동작하는 동안 참조
Java에서 소켓
3가지 타입
- Connection-oriented (TCP)
- Connectionless (UDP)
- MulticastSocket 클래스
- 데이터가 다수의 수신자에게 보내질 수 있음
"Date" 서버 고려
import java.net.* ; import java.io.* ; public class DateServer{ public static void main(String[] args) { try ( ServerSocket sock = new ServerSocket (6013); / * now listen for connections * / while (true) { Socket client = sock.accept(); PrintWriter pout = new PrintWriter(client.getOutputStream(), true); / * write the Date to the socket * / pout.println(new java.util.Date().toStringO); / * close the socket and resume * / / * listening for connections * / client.close(); } } catch (lOException ioe) { System.err.println(ioe); } } }
원격 프로시저 호출 (3.8.2.)
Remote Procedure Call (RPC) 네트워크된 시스템에서 프로세스들 사이에 절차 콜을 추출
- 서비스 차별화를 위해 포트 다시 사용
Stubs
- 서버에서 실제 절차를 위한 클라이언트 프록시
클라이언트 stub은 서버를 찾고, 파라미터를 정리(marshalls)
서버 stub은 이 메시지를 받고, 정리된 파라미터를 해체 후, 서버에서 절차 수행
윈도우에서 stub 코드는 Microsoft Interface Definition Language (MIDL)에서 쓰여진 특성으로부터 컴파일됨
데이터 표현은 External Data Representation(XDL)에 의해 다뤄짐, 다른 아키텍쳐를 설명하기 위해
- big-endian & little-endian
원격 소통은 로컬 보다 많은 실패 상황을 가짐
- 메시지는 기껏해야가 아니라 정확히 한번만 배달되어야함
os는 랑데부 (또는 중개인) 서비스를 제공함, 클라이언트와 서버를 연결하기 위해
파이프 (3.7.4.)
- 두 프로세스가 통신할 수 있는 도관 역할
- 상황
- 커뮤니케이션은 단방향인지 아니면 양방향인지?
- 양방향 통신의 경우, 반이중입니까 아니면 전이중인지?
- 통신 프로세스 사이에 관계(즉, 부모-자녀)가 존재해야 하는지?
- 네트워크를 통해 파이프를 사용할 수 있는지?
전형적인 파이프 (3.7.4.1.)
전형적인 파이프는 기본 생산자-소비자 스타일의 소통을 함
- 생산자는 하나의 끝에 작성(파이프의 write-end)
- 소비자는 다른 끝에서 읽음 (파이프의 read-end)
- 전형적인 파이프는 단방향임
함수 사용 : pipe(int fd[])
fd[0]은 read-end 파이프 부분, fd[1]이 wirte-end
- fd[0]이 소비자, fd[1]이 생산자
부모 프로세스와 자식 프로세스 둘다 파이프의 사용되지 않은 끝단으로 붙어있음
소통 절차에서 부모-자식 관계가 요구
윈도우는 이 익명 파이프를 호출
유닉스와 윈도우 코드 샘플을 책에서 확인
- Unix의 일반 파이프 (과제2 2번 코드)
- (그림 3.23) 참조
- Windows의 일반 파이프
- (그림 3.24), (그림 3.25) 참조
- Unix의 일반 파이프 (과제2 2번 코드)
지명 파이프 (Named Pipe) (3.7.4.1.)
- 네임드 파이프는 더 강력
- 소통은 상호방향
- 부모-자식 관계가 아님
- 몇몇 프로세스는 소통을 위해 네임드 파이프 이용 가능
- 유닉스와 윈도우 시스템 둘다 제공됨
- 하나가 생성되면, 네임드 파이프는 파일 시스템 안에서 전형적인 파일로 나타남
- FIFO는 mkfifo() 시스템 호출로 생성, 일반 open(), read(), write() 및 close() 시스템 호출로 조작
- 파일 시스템에서 명시적으로 삭제될 때까지 계속 존재함
- FIFO는 양방향 통신을 허용하지만 반이중 전송만 허용됨
'학교수업 > 운영체제' 카테고리의 다른 글
운영체제 및 보안 - Lecture 4. Thread (1) | 2025.04.14 |
---|---|
운영체제 및 보안 - Lecture 2. System structures (3) | 2025.04.13 |
운영체제 및 보안 - Lecture 1. Introduction (2) | 2025.04.13 |